@borgar/fx 4.0.0 → 4.2.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 +4 -3
- package/lib/addTokenMeta.js +54 -17
- package/lib/addTokenMeta.spec.js +10 -1
- 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",l="range_beam",r="range_ternary",o="range_named",u="structured",i="unknown",c="UnaryExpression",s="BinaryExpression",a="ReferenceIdentifier",f="CallExpression";function p(e){const t=/(?:\[(.+?)\])?([^[\]]+?)$/.exec(e);if(t){const[,e,n]=t;return{context:[e,n].filter(Boolean)}}}const h=e=>e&&":"===e.value&&{},g=e=>e&&"range"===e.type&&{r0:e.value},d=e=>e&&e.type===r&&{r0:e.value},$=e=>e&&"range"===e.type&&{r1:e.value},y=t=>t&&t.type===e&&"!"===t.value&&{},x=e=>e&&e.type===l&&{r0:e.value},v=e=>e&&e.type===u&&{struct:e.value},m=e=>e&&e.type===n?p(e.value):e&&"context_quote"===e.type?p(e.value.slice(1,-1).replace(/''/g,"'")):void 0,E=e=>e&&e.type===o&&{name:e.value},R=[[d],[g,h,$],[g],[x],[m,y,d],[m,y,g,h,$],[m,y,g],[m,y,x]],w=R.concat([[E],[m,y,E],[v],[E,v],[m,y,E,v]]);function C(e,t){const n={withLocation:!1,mergeRefs:!1,allowTernary:!1,allowNamed:!0,r1c1:!1,...t},l=Ae(e,$e,n),r={context:[],r0:"",r1:"",name:""};l.length&&"fx_prefix"===l[0].type&&l.shift();const o=n.allowNamed?w:R;for(let e=0;e<o.length;e++){const t={...r};if(o[e].length===l.length){const n=o[e].every(((e,n)=>{const r=e(l[n]);return Object.assign(t,r),r}));if(n)return t}}return null}const A=/[^0-9A-Za-z._¡¤§¨ª\u00ad¯-\uffff]/;function N(e){let t="",n=0,l=0;const r=e.context||[];for(let e=r.length;e>-1;e--){const o=r[e];if(o){t=(l%2?"["+o+"]":o)+t,n+=A.test(o),l++}}return n&&(t="'"+t.replace(/'/g,"''")+"'"),t?t+"!":t}const b=(e,t,n)=>Math.min(Math.max(t,e),n),T=(e,t)=>(t?"$":"")+O(e),I=(e,t)=>(t?"$":"")+String(e+1);function L(e){const t=e||"",n=t.length;let l=0;if(n>2){const e=t.charCodeAt(n-3);l+=676*(1+e-(e>95?32:0)-65)}if(n>1){const e=t.charCodeAt(n-2);l+=26*(1+e-(e>95?32:0)-65)}if(n){const e=t.charCodeAt(n-1);l+=e-(e>95?32:0)-65}return l}function O(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 _(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]?L(t[2]):null,!!t[3],!!t[1]]:null;var n}function U(e){let t=null,n=null,l=null,r=null,o=!1,u=!1,i=!1,c=!1;const[s,a,f]=e.split(":");if(f)return null;const p=_(s),h=a?_(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]?[l,r,i,c]=h:null==h[0]&&null!=h[1]?[,r,,c]=h:null!=h[0]&&null==h[1]&&([l,,i]=h);else{if(null==t||null==n)return null;l=t,r=n,i=o,c=u}return null!=r&&(null==n||null!=n&&r<n)&&([n,r,u,c]=[r,n,c,u]),null!=l&&(null==t||null!=t&&l<t)&&([t,l,o,i]=[l,t,i,o]),{top:t,left:n,bottom:l,right:r,$top:o,$left:u,$bottom:i,$right:c}}function F(e){let{allowNamed:t=!0,allowTernary:n=!1}=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const l=C(e,{allowNamed:t,allowTernary:n,r1c1:!1});if(l&&(l.r0||l.name)){let e=null;return l.r0&&(e=U(l.r1?l.r0+":"+l.r1:l.r0)),l.name||e?(l.range=e,delete l.r0,delete l.r1,l):null}return null}function S(e){return N(e)+(e.name?e.name:function(e){let{top:t,left:n,bottom:l,right:r}=e;const{$left:o,$right:u,$top:i,$bottom:c}=e,s=null==n,a=null==r,f=null==t,p=null==l;return t=b(0,0|t,1048575),n=b(0,0|n,16383),!s&&!f&&a&&p?(l=t,r=n):(l=b(0,0|l,1048575),r=b(0,0|r,16383)),0===t&&l>=1048575||f&&p?T(n,o)+":"+T(r,u):0===n&&r>=16383||s&&a?I(t,i)+":"+I(l,c):s||f||a||!p?s||!f||a||p?s||f||!a||p?!s||f||a||p?r!==n||l!==t||u!==o||c!==i?T(n,o)+I(t,i)+":"+T(r,u)+I(l,c):T(n,o)+I(t,i):T(r,u)+I(t,i)+":"+I(l,c):T(n,o)+I(t,i)+":"+I(l,c):T(n,o)+I(l,c)+":"+T(r,u):T(n,o)+I(t,i)+":"+T(r,u)}(e.range))}function M(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 k=/^\[('['#@[\]]|[^'#@[\]])+\]/i,D=/^([^#@[\]:]+)/i,j={headers:1,data:2,totals:4,all:8,"this row":16,"@":16},z=function(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return Object.freeze(t)},W={0:z(),1:z("headers"),2:z("data"),4:z("totals"),8:z("all"),16:z("this row"),3:z("headers","data"),6:z("data","totals")},q=function(e){let t=!(arguments.length>1&&void 0!==arguments[1])||arguments[1],n=k.exec(e);if(n){const e=n[0].slice(1,-1).replace(/'(['#@[\]])/g,"$1");return[n[0],e]}return t&&(n=D.exec(e),n)?[n[0],n[0]]:null};function B(e){const t=[];let n,l,r=0,o=e,u=0;if(!(n=/^(\[\s*)/.exec(o)))return null;if(l=/^\[#([a-z ]+)\]/i.exec(o)){const e=l[1].toLowerCase();if(r+=l[0].length,!j[e])return null;u|=j[e]}else if(l=q(o,!1))r+=l[0].length,t.push(l[1].trim());else{let l=!0;for(o=o.slice(n[1].length),r+=n[1].length;l&&(n=/^\[#([a-z ]+)\](\s*,\s*)?/i.exec(o));){const e=n[1].toLowerCase();if(!j[e])return null;u|=j[e],o=o.slice(n[0].length),r+=n[0].length,l=!!n[2]}if(l&&(n=/^@/.exec(o))&&(u|=j["@"],o=o.slice(1),r+=1,l="]"!==o[0]),!(u in W))return null;const i=l?q(e.slice(r)):null;if(i){if(r+=i[0].length,t.push(i[1].trim()),o=e.slice(r),":"===o[0]){o=o.slice(1),r++;const e=q(o);if(!e)return null;r+=e[0].length,t.push(e[1].trim())}l=!1}for(;" "===e[r];)r++;if(l||"]"!==e[r])return null;r++}const i=W[u];return{columns:t,sections:i?i.concat():i,length:r,token:e.slice(0,r)}}function Z(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const n=C(e,t);if(n&&n.struct){const e=B(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 P(e){return e.replace(/([[\]#'@])/g,"'$1")}function X(e){return e[0].toUpperCase()+e.slice(1).toLowerCase()}function H(e){let t=N(e);e.table&&(t+=e.table);const n=e.columns?.length??0,l=e.sections?.length??0;if(1!==l||n)if(l||1!==n){t+="[";const o=1===l&&"this row"===e.sections[0].toLowerCase();o?t+="@":l&&(t+=e.sections.map((e=>`[#${X(e)}]`)).join(","),n&&(t+=",")),o&&1===e.columns.length&&(r=e.columns[0],/^[a-zA-Z0-9\u00a1-\uffff]+$/.test(r))?t+=P(e.columns[0]):n&&(t+=e.columns.slice(0,2).map((e=>`[${P(e)}]`)).join(":")),t+="]"}else t+=`[${P(e.columns[0])}]`;else t+=`[#${X(e.sections[0])}]`;var r;return t}const Y=/^(\[(?:[^\]])+\])?([0-9A-Za-z._¡¤§¨ª\u00ad¯-\uffff]+)(?=!)/,G=/^'(?:''|[^'])*('|$)(?=!)/,K="\\$?[A-Z]{1,3}\\$?[1-9][0-9]{0,6}",V="\\$?[A-Z]{1,3}",Q="\\$?[1-9][0-9]{0,6}",J=new RegExp(`^${V}:${V}`,"i"),ee=new RegExp(`^${Q}:${Q}`,"i"),te=new RegExp(`^${K}`,"i"),ne=new RegExp(`^((${V}|${Q}):${K}|${K}:(${V}|${Q}))(?![\\w($.])`,"i"),le="(?:R(?:\\[[+-]?\\d+\\]|[1-9][0-9]{0,6})?)",re="(?:C(?:\\[[+-]?\\d+\\]|[1-9][0-9]{0,4})?)",oe=new RegExp(`^${re}(:${re})?(?=\\W|$)`,"i"),ue=new RegExp(`^${le}(:${le})?(?=\\W|$)`,"i"),ie=new RegExp(`^(?:(?=[RC])${le}${re})`,"i"),ce=new RegExp(`^(${le}${re}(:${re}|:${le})(?![[\\d])|(${le}|${re})(:${le}${re}))(?=\\W|$)`,"i"),se=/^(?![CR]\b)[a-zA-Z\\_\u00a1-\uffff][a-zA-Z0-9\\_.?\u00a1-\uffff]{0,254}/i;function ae(e,t){return n=>{const l=t.exec(n);if(l)return{type:e,value:l[0]}}}function fe(e){const t=B(e);if(t){let n=t.length;for(;" "===e[n];)n++;if("!"!==e[n])return{type:u,value:t.token}}return null}const pe=/([RC])(\[?)(-?\d+)/gi,he=/(\d+|[a-zA-Z]+)/gi;function ge(e,t){let n,o;if(t.r1c1){if(t.allowTernary&&(n=ce.exec(e))?o={type:r,value:n[0]}:(n=ie.exec(e))?o={type:"range",value:n[0]}:((n=ue.exec(e))||(n=oe.exec(e)))&&(o={type:l,value:n[0]}),o){for(pe.lastIndex=0;null!==(n=pe.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=ne.exec(e))?o={type:r,value:n[0]}:(n=J.exec(e))||(n=ee.exec(e))?o={type:l,value:n[0]}:(n=te.exec(e))&&(o={type:"range",value:n[0]}),o){for(he.lastIndex=0;null!==(n=he.exec(o.value));)if(/^\d/.test(n[1])){if(parseInt(n[1],10)-1>1048575)return null}else if(L(n[1])>16383)return null;return o}}const de=[ae(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),ae(e,/^(<=|>=|<>|[-+/*^%&<>=]|[{},;]|[()]|@|:|!|#)/),ae("func",/^[A-Z_]+[A-Z\d_.]*(?=\()/i),ae("bool",/^(TRUE|FALSE)\b/i),ae("newline",/^\n+/),ae("whitespace",/^[ \f\r\t\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]+/),ae("string",/^"(?:""|[^"])*("|$)/),ae("context_quote",G),ae(n,Y),ge,fe,ae("number",/^(?:\d+(\.\d+)?(?:[eE][+-]?\d+)?|\d+)/),ae(o,se)],$e=[function(t,n){return n.r1c1?"!"===t[0]?{type:e,value:t[0]}:null:"!"===t[0]||":"===t[0]?{type:e,value:t[0]}:null},ae("context_quote",G),ae(n,Y),ge,fe,ae(o,se)],ye={};function xe(e,t){if(e.length){const n=e[0];t[n]=t[n]||{},xe(e.slice(1),t[n])}else t.$=!0}[["range",":","range"],["range"],[l],[r],[n,"!","range",":","range"],[n,"!","range"],[n,"!",l],[n,"!",r],["context_quote","!","range",":","range"],["context_quote","!","range"],["context_quote","!",l],["context_quote","!",r],[o],[n,"!",o],["context_quote","!",o],[u],[o,u],[n,"!",o,u],["context_quote","!",o,u]].forEach((e=>xe(e.concat().reverse(),ye)));const ve=function(t,n,l){let r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:0;const o=t[l-r];if(o){const u=o.type===e?o.value:o.type;if(u in n)return ve(t,n[u],l,r+1)}return n.$?r:0};function me(e){const t=[];for(let n=e.length-1;n>=0;n--){let l=e[n];const r=ve(e,ye,n);if(r){const t=e.slice(n-r+1,n+1);l={...l},l.value=t.map((e=>e.value)).join(""),l.loc&&t[0].loc&&(l.loc[0]=t[0].loc[0]),n-=r-1}t.unshift(l)}return t}const Ee=(e,t)=>e&&e.type===t,Re={withLocation:!1,mergeRefs:!0,allowTernary:!1,negativeNumbers:!0,r1c1:!1},we=e=>e.type===o||"func"===e.type,Ce=t=>!Ee(t,e)||"%"===t.value||"}"===t.value||")"===t.value||"#"===t.value;function Ae(t,n){let l=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};const r=Object.assign({},Re,l),{withLocation:o,mergeRefs:u,negativeNumbers:c}=r,s=[];let a=0,f=null,p=null,h=null;const g=e=>{const t=e.type===i,n=h&&h.type===i;h&&(t&&n||t&&we(h)||n&&we(e))?(h.value+=e.value,h.type=i,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 l=a,u=t.slice(a);let d="",$="";for(let e=0;e<n.length;e++){const t=n[e](u,r);if(t){d=t.type,$=t.value,a+=$.length;break}}d||(d=i,$=t[a],a++);const y={type:d,value:$,...o?{loc:[l,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(c&&"number"===d){const t=h;if(t&&Ee(t,e)&&"-"===t.value&&(!p||Ee(p,"fx_prefix")||!Ce(p))){const e=s.pop();y.value="-"+$,o&&(y.loc[0]=e.loc[0]),f=p,h=s[s.length-1]}}g(y)}return u?me(s):s}function Ne(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return Ae(e,de,t)}function be(e){return!!e&&("range"===e.type||e.type===l||e.type===r)}function Te(e){return!!e&&("range"===e.type||e.type===l||e.type===r||e.type===u||e.type===o)}function Ie(e){return!!e&&("bool"===e.type||e.type===t||"number"===e.type||"string"===e.type)}function Le(e){return!!e&&e.type===t}function Oe(e){return!!e&&("whitespace"===e.type||"newline"===e.type)}function _e(e){return!!e&&"func"===e.type}function Ue(e){return!!e&&"fx_prefix"===e.type}function Fe(t){return!!t&&t.type===e}const Se="(END)",Me=["ANCHORARRAY","CHOOSE","DROP","IF","IFS","INDEX","INDIRECT","LAMBDA","LET","OFFSET","REDUCE","SINGLE","SWITCH","TAKE","XLOOKUP"],ke=e=>!!e&&(e.type===a||("ErrorLiteral"===e.type||e.type===t)&&"#REF!"===e.value||e.type===s&&(":"===e.operator||" "===e.operator||","===e.operator)||e.type===f&&Me.includes(e.callee.name.toUpperCase())),De={};let je,ze,We,qe=!1,Be=!1;function Ze(e){const t=new Error(e);throw t.source=ze.map((e=>e.value)).join(""),t.sourceOffset=ze.slice(0,We).reduce(((e,t)=>e+t.value),"").length,t}function Pe(){let e,t=We;do{e=ze[++t]}while(e&&(Oe(e)||Fe(e)&&"("===e.value));return(e=>{const t=(e&&e.value)+"";return!(!Te(e)&&(!Fe(e)||":"!==t&&","!==t&&t.trim())&&(!_e(e)||!Me.includes(t.toUpperCase()))&&(!Le(e)||"#REF!"!==t))})(e)}function Xe(){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!==je.id&&Ze(`Expected ${e} but got ${je.id}`),Oe(ze[We])){if(!(ke(t)&&Pe()))for(;Oe(ze[We]);)We++}if(We>=ze.length)return void(je=De[Se]);const n=ze[We];let l;We+=1,n.unterminated&&Ze("Encountered an unterminated token");let r=n.type;return Fe(n)?(l=De[n.value],l||Ze(`Unknown operator ${n.value}`)):Oe(n)?l=De["(WHITESPACE)"]:Ie(n)?l=De.Literal:Te(n)?(l=De[a],r=a):_e(n)?l=De["(FUNCTION)"]:Ze(`Unexpected ${n.type} token: ${n.value}`),je=Object.create(l),je.type=r,je.value=n.value,n.loc&&(je.loc=[...n.loc]),je}function He(e){let t=je;Xe(null,t);let n=t.nud();for(;e<je.lbp;)t=je,Xe(null,t),n=t.led(n);return n}const Ye={nud:()=>Ze("Invalid syntax"),led:()=>Ze("Missing operator")};function Ge(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=De[e];return n?t>=n.lbp&&(n.lbp=t):(n={...Ye},n.id=e,n.value=e,n.lbp=t,De[e]=n),n}function Ke(e,t,n){const l=Ge(e,t);return l.led=n||function(e){this.type=s,this.operator=this.value,delete this.value;const n=He(t);return this.arguments=[e,n],this.loc&&(this.loc=[e.loc[0],n.loc[1]]),this},l}function Ve(e,t){const n=Ge(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 Qe(e,t){const n=Ge(e);return n.nud=t||function(){this.type=c,this.operator=this.value,delete this.value;const e=He(70);return this.arguments=[e],this.loc&&(this.loc[1]=e.loc[1]),this},n}function Je(e,t){return Ke(e,t,(function(n){ke(n)||Ze(`Unexpected ${e} operator`);const l=He(t);return ke(l)||Ze(`Unexpected ${je.type} following ${this.id}`),this.type=s,this.operator=this.value.trim()?this.value:" ",delete this.value,this.arguments=[n,l],this.loc&&(this.loc=[n.loc[0],l.loc[1]]),this}))}Ge(Se),Je(":",80);const et=Je(",",80);Je("(WHITESPACE)",80);const tt=e=>{const t=et.lbp>0;return null!=e&&(et.lbp=e?80:0),t};function nt(){let e=1;return()=>"fxg"+e++}function lt(e,t){return null==e&&null==t||e===t}function rt(e,t){if(Array.isArray(e)!==Array.isArray(t)||e.length!==t.length)return!1;for(let n=0;n<e.length;n++)if(!lt(e[n],t[n]))return!1;return!0}function ot(e,t){return!e&&!t||String(e).toLowerCase()===String(t).toLowerCase()}function ut(e,t){if((e.name||t.name)&&e.name!==t.name)return!1;if(e.columns||t.columns){if(e.table!==t.table)return!1;if(!rt(e.columns,t.columns))return!1;if(!rt(e.sections,t.sections))return!1}return!!(!e.range&&!t.range||lt(e.range.top,t.range.top)&<(e.range.bottom,t.range.bottom)&<(e.range.left,t.range.left)&<(e.range.right,t.range.right))&&!(!ot(e.context[0],t.context[0])||!ot(e.context[1],t.context[1]))}function it(e,t,n){if(e.context.length){if(1===e.context.length){const l=e.context[0];e.context=l===t||l===n?[n,t]:[n,l]}}else e.context=[n,t];return e}Ve("%"),Ve("#",(function(e){return ke(e)||Ze("# expects a reference"),this.type=c,this.operator=this.value,delete this.value,this.arguments=[e],this})),Qe("+"),Qe("-"),Qe("@"),Ke("^",50),Ke("*",40),Ke("/",40),Ke("+",30),Ke("-",30),Ke("&",20),Ke("=",10),Ke("<",10),Ke(">",10),Ke("<=",10),Ke(">=",10),Ke("<>",10),Ge("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},Ge(a).nud=function(){return this.type=a,this},Ge(")"),Qe("(",(function(){const e=tt(!0),t=He(0);return Xe(")",t),tt(e),t})),Ge("(FUNCTION)").nud=function(){return this},Ke("(",90,(function(e){"(FUNCTION)"!==e.id&&Ze("Cannot call a "+e.type);const t=[];let n=!1;if(")"!==je.id){const e=tt(!1);for(;")"!==je.id;)if(Oe(je)&&Xe(),","===je.id)t.push(null),n=!0,Xe();else{const e=He(0);t.push(e),n=!1,","===je.id&&(Xe(","),n=!0)}tt(e)}n&&t.push(null);const l=je;return delete this.value,this.type=f,this.callee={type:"Identifier",name:e.value},e.loc&&(this.callee.loc=[...e.loc]),this.arguments=t,e.loc&&(this.loc=[e.loc[0],l.loc[1]]),Xe(")",this),this})),Ge("}"),Ge(";"),Qe("{",(function(){"}"===je.id&&Ze("Unexpected empty array");let e=[],t=!1;const n=[e],l=tt(!1);for(;!t;){if(Oe(je)&&Xe(),Ie(je))e.push(De.Literal.nud.call(je)),Xe();else if(qe&&ke(je))e.push(De[a].nud.call(je)),Xe();else if(Be&&_e(je)){const t=He(0);e.push(t)}else Ze(`Unexpected ${je.type} in array: ${je.value}`);","===je.id?Xe(","):";"===je.id?(Xe(";"),e=[],n.push(e)):t=!0}const r=je;return Xe("}"),tt(l),this.type="ArrayExpression",this.elements=n,this.loc&&(this.loc[1]=r.loc[1]),delete this.value,this}));const ct=(e,t,n)=>Math.min(Math.max(t,e),n);function st(e,t){return t?String(e+1):e?"["+e+"]":""}function at(e){let t=null,n=null,l=null,r=null;const o=/^R(?:\[([+-]?\d+)\]|(\d+))?/.exec(e);o&&(o[1]?(t=parseInt(o[1],10),l=!1):o[2]?(t=parseInt(o[2],10)-1,l=!0):(t=0,l=!1),e=e.slice(o[0].length));const u=/^C(?:\[([+-]?\d+)\]|(\d+))?/.exec(e);return u&&(u[1]?(n=parseInt(u[1],10),r=!1):u[2]?(n=parseInt(u[2],10)-1,r=!0):(n=0,r=!1),e=e.slice(u[0].length)),!o&&!u||e.length?null:[t,n,l,r]}function ft(e){let t=null;const[n,l]=e.split(":",2),r=at(n);if(r){const[e,n,o,u]=r;if(!l)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 r=at(l);if(!r)return null;{t={};const[l,i,c,s]=r;null!=e&&null!=l?(t.r0=o===c?Math.min(e,l):e,t.$r0=o,t.r1=o===c?Math.max(e,l):l,t.$r1=c):null!=e&&null==l?(t.r0=e,t.$r0=o,t.r1=null,t.$r1=o):null==e&&null!=l?(t.r0=l,t.$r0=c,t.r1=null,t.$r1=c):null==e&&null==l&&(t.r0=null,t.$r0=!1,t.r1=null,t.$r1=!1),null!=n&&null!=i?(t.c0=u===s?Math.min(n,i):n,t.$c0=u,t.c1=u===s?Math.max(n,i):i,t.$c1=s):null!=n&&null==i?(t.c0=n,t.$c0=u,t.c1=null,t.$c1=u):null==n&&null!=i?(t.c0=i,t.$c0=s,t.c1=null,t.$c1=s):null==n&&null==i&&(t.c0=null,t.$c0=!1,t.c1=null,t.$c1=!1)}}}return t}function pt(e){let{allowNamed:t=!0,allowTernary:n=!1}=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const l=C(e,{allowNamed:t,allowTernary:n,r1c1:!0});if(l&&(l.r0||l.name)){const e=l.r1?ft(l.r0+":"+l.r1):ft(l.r0);return l.name||e?(l.range=e,delete l.r0,delete l.r1,l):null}return null}function ht(e){return N(e)+(e.name?e.name:function(e){let{r0:t,c0:n,r1:l,c1:r}=e;const{$c0:o,$c1:u,$r0:i,$r1:c}=e,s=null==t,a=null==n;let f=null==l,p=null==r;if(t=ct(i?0:-1048575,0|t,1048575),n=ct(o?0:-16383,0|n,16383),!s&&f&&!a&&p?(l=t,f=!1,r=n,p=!1):(l=ct(c?0:-1048575,0|l,1048575),r=ct(u?0:-16383,0|r,16383)),0===t&&l>=1048575||s&&f){const e=st(n,o),t=st(r,u);return"C"+(e===t?e:e+":C"+t)}if(0===n&&r>=16383||a&&p){const e=st(t,i),n=st(l,c);return"R"+(e===n?e:e+":R"+n)}const h=st(t,i),g=st(l,c),d=st(n,o),$=st(r,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 gt=(e,t,n)=>null==t?null:e?t:t-n,dt={withLocation:!1,mergeRefs:!1,allowTernary:!0,r1c1:!1};function $t(e,t,n,l){let r=!(arguments.length>4&&void 0!==arguments[4])||arguments[4],o=e;if(null!=o&&!t){if(o=n+e,o<0){if(!r)return NaN;o=l+o+1}if(o>l){if(!r)return NaN;o-=l+1}}return o}const yt={wrapEdges:!0,mergeRefs:!0};const xt=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:l,REF_TERNARY:r,REF_NAMED:o,REF_STRUCT:u,FX_PREFIX:"fx_prefix",UNKNOWN:i}),vt=Object.freeze({UNARY:c,BINARY:s,REFERENCE:a,LITERAL:"Literal",ERROR:"ErrorLiteral",CALL:f,ARRAY:"ArrayExpression",IDENTIFIER:"Identifier"});exports.MAX_COLS=16383,exports.MAX_ROWS=1048575,exports.addA1RangeBounds=M,exports.addTokenMeta=function(e){let{sheetName:t="",workbookName:n=""}=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const o=[];let c=null;const s=nt(),a=[],f=()=>o.length+(c?1:0);return e.forEach(((e,p)=>{if(e.index=p,e.depth=f(),"("===e.value)o.push(e),e.depth=f();else if(")"===e.value){const t=o.pop();if(t){const n=s();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=f());else if("}"===e.value){if(c){const t=s();e.groupId=t,e.depth=c.depth,c.groupId=t}else e.error=!0;c=null}else if("range"===e.type||e.type===l||e.type===r||e.type===u){const l=e.type===u?Z(e.value,{allowTernary:!0}):F(e.value,{allowTernary:!0});if(l&&(l.range||l.columns)){l.source=e.value,it(l,t,n);const r=a.find((e=>ut(e,l)));r?e.groupId=r.groupId:(l.groupId=s(),e.groupId=l.groupId,a.push(l))}}else e.type===i&&(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:l,r1c1:r}=n;if(r)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(t.type===u){const e=H(Z(t.value));n=e.length-t.value.length,t.value=e}else if(be(t)){const e=F(t.value,{allowTernary:!0}),r=e.range;l&&M(r);const o=S(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=L,exports.isError=Le,exports.isFunction=_e,exports.isFxPrefix=Ue,exports.isLiteral=Ie,exports.isOperator=Fe,exports.isRange=be,exports.isReference=Te,exports.isWhitespace=Oe,exports.mergeRefTokens=me,exports.nodeTypes=vt,exports.parse=function(e,t){if("string"==typeof e)ze=Ne(e,{withLocation:!0,...t,mergeRefs:!0});else{if(!Array.isArray(e))throw new Error("Parse requires a string or array of tokens.");ze=e}for(qe=t?.permitArrayRanges,Be=t?.permitArrayCalls,We=0;Oe(ze[We])||Ue(ze[We]);)We++;Xe(),tt(!0);const n=He(0);return Xe(Se),n},exports.parseA1Ref=F,exports.parseR1C1Ref=pt,exports.parseStructRef=Z,exports.stringifyA1Ref=S,exports.stringifyR1C1Ref=ht,exports.stringifyStructRef=H,exports.toCol=O,exports.tokenTypes=xt,exports.tokenize=Ne,exports.translateToA1=function(e,n){let l=arguments.length>2&&void 0!==arguments[2]?arguments[2]:yt;const r=U(n),o="string"==typeof e,u={...yt,...l},i=o?Ne(e,{withLocation:!1,mergeRefs:u.mergeRefs,allowTernary:!0,r1c1:!0}):e;let c=0;return i.forEach((e=>{if(be(e)){const n=e.value,l=pt(n,{allowTernary:!0}),o=l.range,i={},s=$t(o.r0,o.$r0,r.top,1048575,u.wrapEdges),a=$t(o.r1,o.$r1,r.top,1048575,u.wrapEdges);s>a?(i.top=a,i.$top=o.$r1,i.bottom=s,i.$bottom=o.$r0):(i.top=s,i.$top=o.$r0,i.bottom=a,i.$bottom=o.$r1);const f=$t(o.c0,o.$c0,r.left,16383,u.wrapEdges),p=$t(o.c1,o.$c1,r.left,16383,u.wrapEdges);f>p?(i.left=p,i.$left=o.$c1,i.right=f,i.$right=o.$c0):(i.left=f,i.$left=o.$c0,i.right=p,i.$right=o.$c1),isNaN(s)||isNaN(a)||isNaN(f)||isNaN(p)?(e.type=t,e.value="#REF!",delete e.groupId):(l.range=i,e.value=S(l)),e.loc&&(e.loc[0]+=c,c+=e.value.length-n.length,e.loc[1]+=c)}else c&&e.loc&&(e.loc[0]+=c,e.loc[1]+=c)})),o?i.map((e=>e.value)).join(""):i},exports.translateToR1C1=function(e,t){const{top:n,left:l}=U(t),r="string"==typeof e,o=r?Ne(e,dt):e;let u=0;return o.forEach((e=>{if(be(e)){const t=e.value,r=F(t,{allowTernary:!0}),o=r.range,i={};i.r0=gt(o.$top,o.top,n),i.r1=gt(o.$bottom,o.bottom,n),i.c0=gt(o.$left,o.left,l),i.c1=gt(o.$right,o.right,l),i.$r0=o.$top,i.$r1=o.$bottom,i.$c0=o.$left,i.$c1=o.$right,r.range=i,e.value=ht(r),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)})),r?o.map((e=>e.value)).join(""):o};
|
|
2
2
|
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnguanMiLCJzb3VyY2VzIjpbXSwic291cmNlc0NvbnRlbnQiOltdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIn0=
|
package/docs/API.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# _fx_ API
|
|
2
2
|
|
|
3
3
|
## Constants
|
|
4
4
|
|
|
@@ -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/addTokenMeta.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { REF_RANGE, REF_BEAM, REF_TERNARY, UNKNOWN } from './constants.js';
|
|
1
|
+
import { REF_RANGE, REF_BEAM, REF_TERNARY, UNKNOWN, REF_STRUCT } from './constants.js';
|
|
2
2
|
import { parseA1Ref } from './a1.js';
|
|
3
|
+
import { parseStructRef } from './sr.js';
|
|
3
4
|
|
|
4
5
|
function getIDer () {
|
|
5
6
|
let i = 1;
|
|
@@ -13,6 +14,18 @@ function sameValue (a, b) {
|
|
|
13
14
|
return a === b;
|
|
14
15
|
}
|
|
15
16
|
|
|
17
|
+
function sameArray (a, b) {
|
|
18
|
+
if ((Array.isArray(a) !== Array.isArray(b)) || a.length !== b.length) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
for (let i = 0; i < a.length; i++) {
|
|
22
|
+
if (!sameValue(a[i], b[i])) {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
|
|
16
29
|
function sameStr (a, b) {
|
|
17
30
|
if (!a && !b) {
|
|
18
31
|
return true;
|
|
@@ -25,6 +38,18 @@ function isEquivalent (refA, refB) {
|
|
|
25
38
|
if ((refA.name || refB.name) && refA.name !== refB.name) {
|
|
26
39
|
return false;
|
|
27
40
|
}
|
|
41
|
+
// if structured
|
|
42
|
+
if ((refA.columns || refB.columns)) {
|
|
43
|
+
if (refA.table !== refB.table) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
if (!sameArray(refA.columns, refB.columns)) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
if (!sameArray(refA.sections, refB.sections)) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
28
53
|
// if ranged, range must have the same dimensions (we don't care about $)
|
|
29
54
|
if (refA.range || refB.range) {
|
|
30
55
|
if (
|
|
@@ -46,6 +71,23 @@ function isEquivalent (refA, refB) {
|
|
|
46
71
|
return true;
|
|
47
72
|
}
|
|
48
73
|
|
|
74
|
+
function addContext (ref, sheetName, workbookName) {
|
|
75
|
+
if (!ref.context.length) {
|
|
76
|
+
ref.context = [ workbookName, sheetName ];
|
|
77
|
+
}
|
|
78
|
+
else if (ref.context.length === 1) {
|
|
79
|
+
const scope = ref.context[0];
|
|
80
|
+
if (scope === sheetName || scope === workbookName) {
|
|
81
|
+
ref.context = [ workbookName, sheetName ];
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
// a single scope on a non-named range is going to be a sheet name
|
|
85
|
+
ref.context = [ workbookName, scope ];
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return ref;
|
|
89
|
+
}
|
|
90
|
+
|
|
49
91
|
/**
|
|
50
92
|
* Runs through a list of tokens and adds extra attributes such as matching
|
|
51
93
|
* parens and ranges.
|
|
@@ -140,23 +182,18 @@ export function addTokenMeta (tokens, { sheetName = '', workbookName = '' } = {}
|
|
|
140
182
|
}
|
|
141
183
|
arrayStart = null;
|
|
142
184
|
}
|
|
143
|
-
else if (
|
|
144
|
-
|
|
145
|
-
|
|
185
|
+
else if (
|
|
186
|
+
token.type === REF_RANGE ||
|
|
187
|
+
token.type === REF_BEAM ||
|
|
188
|
+
token.type === REF_TERNARY ||
|
|
189
|
+
token.type === REF_STRUCT
|
|
190
|
+
) {
|
|
191
|
+
const ref = (token.type === REF_STRUCT)
|
|
192
|
+
? parseStructRef(token.value, { allowTernary: true })
|
|
193
|
+
: parseA1Ref(token.value, { allowTernary: true });
|
|
194
|
+
if (ref && (ref.range || ref.columns)) {
|
|
146
195
|
ref.source = token.value;
|
|
147
|
-
|
|
148
|
-
ref.context = [ workbookName, sheetName ];
|
|
149
|
-
}
|
|
150
|
-
else if (ref.context.length === 1) {
|
|
151
|
-
const scope = ref.context[0];
|
|
152
|
-
if (scope === sheetName || scope === workbookName) {
|
|
153
|
-
ref.context = [ workbookName, sheetName ];
|
|
154
|
-
}
|
|
155
|
-
else {
|
|
156
|
-
// a single scope on a non-named range is going to be a sheet name
|
|
157
|
-
ref.context = [ workbookName, scope ];
|
|
158
|
-
}
|
|
159
|
-
}
|
|
196
|
+
addContext(ref, sheetName, workbookName);
|
|
160
197
|
const known = knownRefs.find(d => isEquivalent(d, ref));
|
|
161
198
|
if (known) {
|
|
162
199
|
token.groupId = known.groupId;
|
package/lib/addTokenMeta.spec.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { test, Test } from 'tape';
|
|
2
|
-
import { FX_PREFIX, OPERATOR, NUMBER, REF_RANGE, REF_BEAM, FUNCTION, WHITESPACE } from './constants.js';
|
|
2
|
+
import { FX_PREFIX, OPERATOR, NUMBER, REF_RANGE, REF_BEAM, FUNCTION, WHITESPACE, REF_STRUCT } from './constants.js';
|
|
3
3
|
import { addTokenMeta } from './addTokenMeta.js';
|
|
4
4
|
import { tokenize } from './lexer.js';
|
|
5
5
|
|
|
@@ -106,5 +106,14 @@ test('add extra meta to operators', t => {
|
|
|
106
106
|
{ index: 17, depth: 1, type: OPERATOR, value: ')', groupId: 'fxg3' }
|
|
107
107
|
], { sheetName: 'Sheet1', workbookName: 'foo' });
|
|
108
108
|
|
|
109
|
+
t.isMetaTokens('=table[#all]+table[foobar]+table[[#All]]', [
|
|
110
|
+
{ index: 0, depth: 0, type: FX_PREFIX, value: '=' },
|
|
111
|
+
{ index: 1, depth: 0, type: REF_STRUCT, value: 'table[#all]', groupId: 'fxg1' },
|
|
112
|
+
{ index: 2, depth: 0, type: OPERATOR, value: '+' },
|
|
113
|
+
{ index: 3, depth: 0, type: REF_STRUCT, value: 'table[foobar]', groupId: 'fxg2' },
|
|
114
|
+
{ index: 4, depth: 0, type: OPERATOR, value: '+' },
|
|
115
|
+
{ index: 5, depth: 0, type: REF_STRUCT, value: 'table[[#All]]', groupId: 'fxg1' }
|
|
116
|
+
], { sheetName: 'Sheet1', workbookName: 'foo' });
|
|
117
|
+
|
|
109
118
|
t.end();
|
|
110
119
|
});
|
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.2.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": {
|