@borgar/fx 3.0.0-rc.0 → 3.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/README.md CHANGED
@@ -212,7 +212,7 @@ a1.stringify({
212
212
  top: 0,
213
213
  left: 0,
214
214
  bottom: 1,
215
- right: 1
215
+ right: 1,
216
216
  $top: true,
217
217
  $left: false,
218
218
  $bottom: false,
@@ -254,13 +254,13 @@ a1.addBounds({
254
254
  // }
255
255
  ```
256
256
 
257
- #### <a name="a1.to" href="#a1.to">#</a> **.to**( _columnString_ )
257
+ #### <a name="a1.to" href="#a1.to">#</a> **.to**( _rangeObject_ )
258
258
 
259
- Parse a simple string reference to an A1 range into a range object ([see above](#a1.parse)). Will accept `A1`, `A2`, `A:A`, or `1:1`.
259
+ Stringify a range object ([see above](#a1.parse)) into A1 syntax.
260
260
 
261
- #### <a name="a1.from" href="#a1.from">#</a> **.from**( _rangeObject_ )
261
+ #### <a name="a1.from" href="#a1.from">#</a> **.from**( _rangeString_ )
262
262
 
263
- Stringify a range object ([see above](#a1.parse)) into A1 syntax.
263
+ Parse a simple string reference to an A1 range into a range object ([see above](#a1.parse)). Will accept `A1`, `A2`, `A:A`, or `1:1`.
264
264
 
265
265
  #### <a name="a1.fromCol" href="#a1.fromCol">#</a> **.fromCol**( _columnString_ )
266
266
 
@@ -319,10 +319,10 @@ a1.stringify({
319
319
  ```
320
320
 
321
321
 
322
- #### <a name="rc.from" href="#rc.from">#</a> **.from**( _rangeObject_ )
322
+ #### <a name="rc.from" href="#rc.from">#</a> **.from**( _refString_ )
323
323
 
324
- Stringify a range object ([see above](#rc.parse)) into R1C1 syntax.
325
-
326
- #### <a name="rc.to" href="#rc.to">#</a> **.to**( _columnString_ )
327
324
  Parse a simple string reference to an R1C1 range into a range object ([see above](#rc.parse)).
328
325
 
326
+ #### <a name="rc.to" href="#rc.to">#</a> **.to**( _rangeObject_ )
327
+
328
+ Stringify a range object ([see above](#rc.parse)) into R1C1 syntax.
package/dist/fx.js CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";const e="range",t="unknown";function n(e){const t=/(?:\[(.+?)\])?([^[\]]+?)$/.exec(e);if(t){const[,e,n]=t;return{context:[e,n].filter(Boolean)}}}const r=e=>e&&":"===e.value&&{},l=t=>t&&t.type===e&&{r0:t.value},o=e=>e&&"range_ternary"===e.type&&{r0:e.value},u=t=>t&&t.type===e&&{r1:t.value},a=e=>e&&"operator"===e.type&&"!"===e.value&&{},c=e=>e&&"range_beam"===e.type&&{r0:e.value},i=e=>e&&"context"===e.type?n(e.value):e&&"context_quote"===e.type?n(e.value.slice(1,-1).replace(/''/g,"'")):void 0,f=e=>e&&"range_named"===e.type&&{name:e.value},s=[[o],[l,r,u],[l],[c],[i,a,o],[i,a,l,r,u],[i,a,l],[i,a,c]],g=s.concat([[f],[i,a,f]]);function p(e,t){const n={emitRanges:!1,mergeRanges:!1,allowTernary:!1,allowNamed:!0,r1c1:!1,...t},r=re(e,K,n),l={context:[],r0:"",r1:"",name:""};r.length&&"fx_prefix"===r[0].type&&r.shift();const o=n.allowNamed?g:s;for(let e=0;e<o.length;e++){const t={...l};if(o[e].length===r.length){if(o[e].every(((e,n)=>{const l=e(r[n]);return Object.assign(t,l),l})))return t}}return null}const $=/[^0-9A-Za-z._¡¤§¨ª\u00ad¯-\uffff]/;function m(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+=$.test(o),r++}}return n&&(t="'"+t.replace(/'/g,"''")+"'"),t?t+"!":t}function d(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 x(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)}const h=(e,t)=>(t?"$":"")+x(e),y=(e,t)=>(t?"$":"")+String(e+1);function v(e){const{top:t,left:n,bottom:r,right:l,$left:o,$right:u,$top:a,$bottom:c}=e,i=null==n,f=null==l,s=null==t,g=null==r;return 0===t&&r>=1048575||s&&g?h(n,o)+":"+h(l,u):0===n&&l>=16383||i&&f?y(t,a)+":"+y(r,c):i||s||f||!g?i||!s||f||g?i||s||!f||g?!i||s||f||g?l!==n||r!==t||u!==o||c!==a?h(n,o)+y(t,a)+":"+h(l,u)+y(r,c):h(n,o)+y(t,a):h(l,u)+y(t,a)+":"+y(r,c):h(n,o)+y(t,a)+":"+y(r,c):h(n,o)+y(r,c)+":"+h(l,u):h(n,o)+y(t,a)+":"+h(l,u)}function R(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]?d(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,a=!1,c=!1;const[i,f,s]=e.split(":");if(s)return null;const g=R(i),p=f?R(f):null;if(!g||f&&!p)return null;if(null!=g[0]&&null!=g[1]?[t,n,o,u]=g:null==g[0]&&null!=g[1]?[,n,,u]=g:null!=g[0]&&null==g[1]&&([t,,o]=g),f)null!=p[0]&&null!=p[1]?[r,l,a,c]=p:null==p[0]&&null!=p[1]?[,l,,c]=p:null!=p[0]&&null==p[1]&&([r,,a]=p);else{if(null==t||null==n)return null;r=t,l=n,a=o,c=u}return null!=l&&(null==n||null!=n&&l<n)&&([n,l,u,c]=[l,n,c,u]),null!=r&&(null==t||null!=t&&r<t)&&([t,r,o,a]=[r,t,a,o]),{top:t,left:n,bottom:r,right:l,$top:o,$left:u,$bottom:a,$right:c}}function b(e){let{allowNamed:t=!0,allowTernary:n=!1}=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const r=p(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 E(e){return m(e)+(e.name?e.name:v(e.range))}function w(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}var A={fromCol:d,toCol:x,toRelative:function(e){const{top:t,left:n,bottom:r,right:l}=e;return{top:t,left:n,bottom:r,right:l,$left:!1,$right:!1,$top:!1,$bottom:!1}},toAbsolute:function(e){const{top:t,left:n,bottom:r,right:l}=e;return{top:t,left:n,bottom:r,right:l,$left:!0,$right:!0,$top:!0,$bottom:!0}},to:v,from:_,parse:b,addBounds:w,stringify:E};const N=/^(\[(?:[^\]])+\])?([0-9A-Za-z._¡¤§¨ª\u00ad¯-\uffff]+)(?=!)/,C=/^'(?:''|[^'])*('|$)(?=!)/,T="\\$?[A-Z]{1,3}\\$?[1-9][0-9]{0,6}",I="\\$?[A-Z]{1,3}",O="\\$?[1-9][0-9]{0,6}",L=new RegExp(`^${I}:${I}`,"i"),S=new RegExp(`^${O}:${O}`,"i"),M=new RegExp(`^${T}`,"i"),Z=new RegExp(`^((${I}|${O}):${T}|${T}:(${I}|${O}))(?![\\w($.])`,"i"),q="(?:R(?:\\[[+-]?\\d+\\]|[1-9][0-9]{0,6})?)",U="(?:C(?:\\[[+-]?\\d+\\]|[1-9][0-9]{0,4})?)",W=new RegExp(`^${U}(:${U})?(?=\\W|$)`,"i"),k=new RegExp(`^${q}(:${q})?(?=\\W|$)`,"i"),z=new RegExp(`^(?:(?=[RC])${q}${U})`,"i"),B=new RegExp(`^(${q}${U}(:${U}|:${q})(?![[\\d])|(${q}|${U})(:${q}${U}))(?=\\W|$)`,"i"),F=/^[a-zA-Z\\_\u00a1-\uffff][a-zA-Z0-9\\_.?\u00a1-\uffff]{0,254}/i;function G(e,t){return n=>{const r=t.exec(n);if(r)return{type:e,value:r[0]}}}const X=/([RC])(\[?)(-?\d+)/gi,j=/(\d+|[a-zA-Z]+)/gi;function D(t,n){let r,l;if(n.r1c1){if(n.allowTernary&&(r=B.exec(t))?l={type:"range_ternary",value:r[0]}:(r=z.exec(t))?l={type:e,value:r[0]}:((r=k.exec(t))||(r=W.exec(t)))&&(l={type:"range_beam",value:r[0]}),l){for(X.lastIndex=0;null!==(r=X.exec(l.value));){const e=("R"===r[1]?1048575:16383)+(r[2]?1:0),t=parseInt(r[3],10);if(t>=e||t<=-e)return null}return l}}else if(n.allowTernary&&(r=Z.exec(t))?l={type:"range_ternary",value:r[0]}:(r=L.exec(t))||(r=S.exec(t))?l={type:"range_beam",value:r[0]}:(r=M.exec(t))&&(l={type:e,value:r[0]}),l){for(j.lastIndex=0;null!==(r=j.exec(l.value));)if(/^\d/.test(r[1])){if(parseInt(r[1],10)-1>1048575)return null}else if(d(r[1])>16383)return null;return l}}const P=[G("error",/^#(NAME\?|FIELD!|CALC!|VALUE!|REF!|DIV\/0!|NULL!|NUM!|N\/A|GETTING_DATA\b|SPILL!|UNKNOWN!|FIELD\b|CALC\b|SYNTAX\?|ERROR!)/i),G("operator",/^(<=|>=|<>|[-+/*^%&<>=]|[{},;]|[()]|@|:|!|#)/),G("bool",/^(TRUE|FALSE)\b/i),G("func",/^[A-Z_]+[A-Z\d_.]*(?=\()/i),G("newline",/^\n+/),G("whitespace",/^[ \f\r\t\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]+/),G("string",/^"(?:""|[^"])*("|$)/),G("context_quote",C),G("context",N),D,G("number",/^(?:\d+(\.\d+)?(?:[eE][+-]?\d+)?|\d+)/),G("range_named",F)],K=[function(e,t){return t.r1c1?"!"===e[0]?{type:"operator",value:e[0]}:null:"!"===e[0]||":"===e[0]?{type:"operator",value:e[0]}:null},G("context_quote",C),G("context",N),D,G("range_named",F)],V={};function Y(e,t){if(e.length){const n=e[0];t[n]=t[n]||{},Y(e.slice(1),t[n])}else t.$=!0}[[e,":",e],[e],["range_beam"],["range_ternary"],["context","!",e,":",e],["context","!",e],["context","!","range_beam"],["context","!","range_ternary"],["context_quote","!",e,":",e],["context_quote","!",e],["context_quote","!","range_beam"],["context_quote","!","range_ternary"],["range_named"],["context","!","range_named"],["context_quote","!","range_named"]].forEach((e=>Y(e.concat().reverse(),V)));const H=function(e,t,n){let r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:0;const l=e[n-r];if(l){const o="operator"===l.type?l.value:l.type;if(o in t)return H(e,t[o],n,r+1)}return t.$?r:0};function Q(e){const t=[];for(let n=e.length-1;n>=0;n--){let r=e[n];const l=H(e,V,n);if(l){const t=e.slice(n-l+1,n+1);r={...r},r.value=t.map((e=>e.value)).join(""),r.range&&t[0].range&&(r.range[0]=t[0].range[0]),n-=l-1}t.unshift(r)}return t}const J=(e,t)=>e&&e.type===t,ee={emitRanges:!1,mergeRanges:!0,allowTernary:!1,negativeNumbers:!0,r1c1:!1},te=e=>"range_named"===e.type||"func"===e.type,ne=e=>!J(e,"operator")||"%"===e.value||"}"===e.value||")"===e.value||"#"===e.value;function re(e,n){let r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};const l=Object.assign({},ee,r),{emitRanges:o,mergeRanges:u,negativeNumbers:a}=l,c=[];let i=0,f=null,s=null,g=null;const p=e=>{const n=e.type===t,r=g&&g.type===t;g&&(n&&r||n&&te(g)||r&&te(e))?(g.value+=e.value,g.type=t,o&&(g.range[1]=e.range[1])):(c.push(e),g=e,"whitespace"!==e.type&&"newline"!==e.type&&(s=f,f=e))};if(/^=/.test(e)){i++,p({type:"fx_prefix",value:"=",...o?{range:[0,1]}:{}})}for(;i<e.length;){const r=i,u=e.slice(i);let $="",m="";for(let e=0;e<n.length;e++){const t=n[e](u,l);if(t){$=t.type,m=t.value,i+=m.length;break}}$||($=t,m=e[i],i++);const d={type:$,value:m,...o?{range:[r,i]}:{}};if("string"===$){const e=m.length;if('""'===m);else if('"'===m||'"'!==m[e-1])d.unterminated=!0;else if('""'!==m&&'"'===m[e-2]){let t=e-1;for(;'"'===m[t];)t--;!(t+1)^(e-t+1)%2==0&&(d.unterminated=!0)}}if(a&&"number"===$){const e=g;if(e&&J(e,"operator")&&"-"===e.value&&(!s||J(s,"fx_prefix")||!ne(s))){const e=c.pop();d.value="-"+m,o&&(d.range[0]=e.range[0]),f=s,g=c[c.length-1]}}p(d)}return u?Q(c):c}function le(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return re(e,P,t)}function oe(){let e=1;return()=>"fxg"+e++}function ue(e,t){return null==e&&null==t||e===t}function ae(e,t){return!e&&!t||String(e).toLowerCase()===String(t).toLowerCase()}function ce(e,t){return(!e.name&&!t.name||e.name===t.name)&&(!!(!e.range&&!t.range||ue(e.range.top,t.range.top)&&ue(e.range.bottom,t.range.bottom)&&ue(e.range.left,t.range.left)&&ue(e.range.right,t.range.right))&&!(!ae(e.context[0],t.context[0])||!ae(e.context[1],t.context[1])))}function ie(e,t){return t?String(e+1):e?"["+e+"]":""}function fe(e){const{r0:t,c0:n,r1:r,c1:l,$c0:o,$c1:u,$r0:a,$r1:c}=e,i=null==t,f=null==r,s=null==n,g=null==l;if(0===t&&r>=1048575||i&&f){const e=ie(n,o),t=ie(l,u);return"C"+(e===t?e:e+":C"+t)}if(0===n&&l>=16383||s&&g){const e=ie(t,a),n=ie(r,c);return"R"+(e===n?e:e+":R"+n)}const p=ie(t,a),$=ie(r,c),m=ie(n,o),d=ie(l,u);return i||f||s||g?(i?"":"R"+p)+(s?"":"C"+m)+":"+(f?"":"R"+$)+(g?"":"C"+d):p!==$||m!==d?"R"+p+"C"+m+":R"+$+"C"+d:"R"+p+"C"+m}function se(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 ge(e){let t=null;const[n,r]=e.split(":",2),l=se(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=se(r);if(!l)return null;{t={};const[r,a,c,i]=l;null!=e&&null!=r?(t.r0=o===c?Math.min(e,r):e,t.$r0=o,t.r1=o===c?Math.max(e,r):r,t.$r1=c):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=c,t.r1=null,t.$r1=c):null==e&&null==r&&(t.r0=null,t.$r0=!1,t.r1=null,t.$r1=!1),null!=n&&null!=a?(t.c0=u===i?Math.min(n,a):n,t.$c0=u,t.c1=u===i?Math.max(n,a):a,t.$c1=i):null!=n&&null==a?(t.c0=n,t.$c0=u,t.c1=null,t.$c1=u):null==n&&null!=a?(t.c0=a,t.$c0=i,t.c1=null,t.$c1=i):null==n&&null==a&&(t.c0=null,t.$c0=!1,t.c1=null,t.$c1=!1)}}}return t}var pe={to:fe,from:ge,parse:function(e){let{allowNamed:t=!0,allowTernary:n=!1}=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const r=p(e,{allowNamed:t,allowTernary:n,r1c1:!0});if(r&&(r.r0||r.name)){const e=r.r1?ge(r.r0+":"+r.r1):ge(r.r0);return r.name||e?(r.range=e,delete r.r0,delete r.r1,r):null}return null},stringify:function(e){return m(e)+(e.name?e.name:fe(e.range))}};function $e(t){return!!t&&(t.type===e||"range_beam"===t.type||"range_ternary"===t.type)}const me=(e,t,n)=>null==t?null:e?t:t-n;function de(e,t,n,r){let l=e;return null==l||t||(l=n+e,l<0&&(l=r+l+1),l>r&&(l-=r+1)),l}const xe={OPERATOR:"operator",BOOLEAN:"bool",ERROR:"error",NUMBER:"number",FUNCTION:"func",NEWLINE:"newline",WHITESPACE:"whitespace",STRING:"string",CONTEXT:"context",CONTEXT_QUOTE:"context_quote",RANGE:e,RANGE_BEAM:"range_beam",RANGE_TERNARY:"range_ternary",RANGE_NAMED:"range_named",FX_PREFIX:"fx_prefix",UNKNOWN:t};exports.MAX_COLS=16383,exports.MAX_ROWS=1048575,exports.a1=A,exports.addMeta=function(n){let{sheetName:r="",workbookName:l=""}=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const o=[];let u=null;const a=oe(),c=[],i=()=>o.length+(u?1:0);return n.forEach(((n,f)=>{if(n.index=f,n.depth=i(),"("===n.value)o.push(n),n.depth=i();else if(")"===n.value){const e=o.pop();if(e){const t=a();n.groupId=t,n.depth=e.depth,e.groupId=t}else n.error=!0}else if("{"===n.value)u?n.error=!0:(u=n,n.depth=i());else if("}"===n.value){if(u){const e=a();n.groupId=e,n.depth=u.depth,u.groupId=e}else n.error=!0;u=null}else if(n.type===e||"range_beam"===n.type||"range_ternary"===n.type){const e=b(n.value,{allowNamed:!1,allowTernary:!0});if(e&&e.range){if(e.source=n.value,e.context.length){if(1===e.context.length){const t=e.context[0];e.context=t===r||t===l?[l,r]:[l,t]}}else e.context=[l,r];const t=c.find((t=>ce(t,e)));t?n.groupId=t.groupId:(e.groupId=a(),n.groupId=e.groupId,c.push(e))}}else n.type===t&&(n.error=!0)})),n},exports.fixRanges=function e(t){let n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{addBounds:!1};if("string"==typeof t)return e(le(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");return t.map((e=>{if($e(e)){const t=b(e.value,n),l=t.range;r&&w(l);const o={...e};return o.value=E(t),o.range&&(o.range=l),o}return e}))},exports.isRange=$e,exports.isReference=function(t){return!!t&&(t.type===e||"range_beam"===t.type||"range_ternary"===t.type||"range_named"===t.type)},exports.mergeRanges=Q,exports.rc=pe,exports.tokenTypes=xe,exports.tokenize=le,exports.translateToA1=function(e,t){const n=_(t),r="string"==typeof e,l=r?le(e,{emitRanges:!1,mergeRanges:!1,allowTernary:!0,r1c1:!0}):e;return l.forEach((e=>{if($e(e)){const t={},r=ge(e.value),l=de(r.r0,r.$r0,n.top,1048575),o=de(r.r1,r.$r1,n.top,1048575);l>o?(t.top=o,t.$top=r.$r1,t.bottom=l,t.$bottom=r.$r0):(t.top=l,t.$top=r.$r0,t.bottom=o,t.$bottom=r.$r1);const u=de(r.c0,r.$c0,n.left,16383),a=de(r.c1,r.$c1,n.left,16383);u>a?(t.left=a,t.$left=r.$c1,t.right=u,t.$right=r.$c0):(t.left=u,t.$left=r.$c0,t.right=a,t.$right=r.$c1),e.value=v(t)}})),r?l.map((e=>e.value)).join(""):l},exports.translateToRC=function(e,t){const{top:n,left:r}=_(t),l="string"==typeof e,o=l?le(e,{emitRanges:!1,mergeRanges:!1,allowTernary:!0,r1c2:!1}):e;return o.forEach((e=>{if($e(e)){const t={},l=_(e.value);t.r0=me(l.$top,l.top,n),t.$r0=l.$top,t.r1=me(l.$bottom,l.bottom,n),t.$r1=l.$bottom,t.c0=me(l.$left,l.left,r),t.$c0=l.$left,t.c1=me(l.$right,l.right,r),t.$c1=l.$right,e.value=fe(t)}})),l?o.map((e=>e.value)).join(""):o};
1
+ "use strict";const e="range",n="unknown";function t(e){const n=/(?:\[(.+?)\])?([^[\]]+?)$/.exec(e);if(n){const[,e,t]=n;return{context:[e,t].filter(Boolean)}}}const r=e=>e&&":"===e.value&&{},l=n=>n&&n.type===e&&{r0:n.value},o=e=>e&&"range_ternary"===e.type&&{r0:e.value},a=n=>n&&n.type===e&&{r1:n.value},u=e=>e&&"operator"===e.type&&"!"===e.value&&{},c=e=>e&&"range_beam"===e.type&&{r0:e.value},i=e=>e&&"context"===e.type?t(e.value):e&&"context_quote"===e.type?t(e.value.slice(1,-1).replace(/''/g,"'")):void 0,g=e=>e&&"range_named"===e.type&&{name:e.value},f=[[o],[l,r,a],[l],[c],[i,u,o],[i,u,l,r,a],[i,u,l],[i,u,c]],s=f.concat([[g],[i,u,g]]);function p(e,n){const t={emitRanges:!1,mergeRanges:!1,allowTernary:!1,allowNamed:!0,r1c1:!1,...n},r=re(e,K,t),l={context:[],r0:"",r1:"",name:""};r.length&&"fx_prefix"===r[0].type&&r.shift();const o=t.allowNamed?s:f;for(let e=0;e<o.length;e++){const n={...l};if(o[e].length===r.length){if(o[e].every(((e,t)=>{const l=e(r[t]);return Object.assign(n,l),l})))return n}}return null}const $=/[^0-9A-Za-z._¡¤§¨ª\u00ad¯-\uffff]/;function m(e){let n="",t=0,r=0;const l=e.context||[];for(let e=l.length;e>-1;e--){const o=l[e];if(o){n=(r%2?"["+o+"]":o)+n,t+=$.test(o),r++}}return t&&(n="'"+n.replace(/'/g,"''")+"'"),n?n+"!":n}function d(e){const n=e||"",t=n.length;let r=0;if(t>2){const e=n.charCodeAt(t-3);r+=676*(1+e-(e>95?32:0)-65)}if(t>1){const e=n.charCodeAt(t-2);r+=26*(1+e-(e>95?32:0)-65)}if(t){const e=n.charCodeAt(t-1);r+=e-(e>95?32:0)-65}return r}function h(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)}const x=(e,n)=>(n?"$":"")+h(e),y=(e,n)=>(n?"$":"")+String(e+1);function v(e){const{top:n,left:t,bottom:r,right:l,$left:o,$right:a,$top:u,$bottom:c}=e,i=null==t,g=null==l,f=null==n,s=null==r;return 0===n&&r>=1048575||f&&s?x(t,o)+":"+x(l,a):0===t&&l>=16383||i&&g?y(n,u)+":"+y(r,c):i||f||g||!s?i||!f||g||s?i||f||!g||s?!i||f||g||s?l!==t||r!==n||a!==o||c!==u?x(t,o)+y(n,u)+":"+x(l,a)+y(r,c):x(t,o)+y(n,u):x(l,a)+y(n,u)+":"+y(r,c):x(t,o)+y(n,u)+":"+y(r,c):x(t,o)+y(r,c)+":"+x(l,a):x(t,o)+y(n,u)+":"+x(l,a)}function R(e){const n=/^(?=.)(\$(?=\D))?([A-Za-z]{0,3})?(\$)?([1-9][0-9]{0,6})?$/.exec(e);return n&&(n[2]||n[4])?[n[4]?(t=n[4],+t-1):null,n[2]?d(n[2]):null,!!n[3],!!n[1]]:null;var t}function _(e){let n=null,t=null,r=null,l=null,o=!1,a=!1,u=!1,c=!1;const[i,g,f]=e.split(":");if(f)return null;const s=R(i),p=g?R(g):null;if(!s||g&&!p)return null;if(null!=s[0]&&null!=s[1]?[n,t,o,a]=s:null==s[0]&&null!=s[1]?[,t,,a]=s:null!=s[0]&&null==s[1]&&([n,,o]=s),g)null!=p[0]&&null!=p[1]?[r,l,u,c]=p:null==p[0]&&null!=p[1]?[,l,,c]=p:null!=p[0]&&null==p[1]&&([r,,u]=p);else{if(null==n||null==t)return null;r=n,l=t,u=o,c=a}return null!=l&&(null==t||null!=t&&l<t)&&([t,l,a,c]=[l,t,c,a]),null!=r&&(null==n||null!=n&&r<n)&&([n,r,o,u]=[r,n,u,o]),{top:n,left:t,bottom:r,right:l,$top:o,$left:a,$bottom:u,$right:c}}function b(e){let{allowNamed:n=!0,allowTernary:t=!1}=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const r=p(e,{allowNamed:n,allowTernary:t,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 E(e){return m(e)+(e.name?e.name:v(e.range))}function w(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}var N={fromCol:d,toCol:h,toRelative:function(e){const{top:n,left:t,bottom:r,right:l}=e;return{top:n,left:t,bottom:r,right:l,$left:!1,$right:!1,$top:!1,$bottom:!1}},toAbsolute:function(e){const{top:n,left:t,bottom:r,right:l}=e;return{top:n,left:t,bottom:r,right:l,$left:!0,$right:!0,$top:!0,$bottom:!0}},to:v,from:_,parse:b,addBounds:w,stringify:E};const A=/^(\[(?:[^\]])+\])?([0-9A-Za-z._¡¤§¨ª\u00ad¯-\uffff]+)(?=!)/,C=/^'(?:''|[^'])*('|$)(?=!)/,T="\\$?[A-Z]{1,3}\\$?[1-9][0-9]{0,6}",I="\\$?[A-Z]{1,3}",O="\\$?[1-9][0-9]{0,6}",L=new RegExp(`^${I}:${I}`,"i"),S=new RegExp(`^${O}:${O}`,"i"),M=new RegExp(`^${T}`,"i"),Z=new RegExp(`^((${I}|${O}):${T}|${T}:(${I}|${O}))(?![\\w($.])`,"i"),q="(?:R(?:\\[[+-]?\\d+\\]|[1-9][0-9]{0,6})?)",U="(?:C(?:\\[[+-]?\\d+\\]|[1-9][0-9]{0,4})?)",B=new RegExp(`^${U}(:${U})?(?=\\W|$)`,"i"),W=new RegExp(`^${q}(:${q})?(?=\\W|$)`,"i"),X=new RegExp(`^(?:(?=[RC])${q}${U})`,"i"),k=new RegExp(`^(${q}${U}(:${U}|:${q})(?![[\\d])|(${q}|${U})(:${q}${U}))(?=\\W|$)`,"i"),z=/^[a-zA-Z\\_\u00a1-\uffff][a-zA-Z0-9\\_.?\u00a1-\uffff]{0,254}/i;function D(e,n){return t=>{const r=n.exec(t);if(r)return{type:e,value:r[0]}}}const F=/([RC])(\[?)(-?\d+)/gi,G=/(\d+|[a-zA-Z]+)/gi;function j(n,t){let r,l;if(t.r1c1){if(t.allowTernary&&(r=k.exec(n))?l={type:"range_ternary",value:r[0]}:(r=X.exec(n))?l={type:e,value:r[0]}:((r=W.exec(n))||(r=B.exec(n)))&&(l={type:"range_beam",value:r[0]}),l){for(F.lastIndex=0;null!==(r=F.exec(l.value));){const e=("R"===r[1]?1048575:16383)+(r[2]?1:0),n=parseInt(r[3],10);if(n>=e||n<=-e)return null}return l}}else if(t.allowTernary&&(r=Z.exec(n))?l={type:"range_ternary",value:r[0]}:(r=L.exec(n))||(r=S.exec(n))?l={type:"range_beam",value:r[0]}:(r=M.exec(n))&&(l={type:e,value:r[0]}),l){for(G.lastIndex=0;null!==(r=G.exec(l.value));)if(/^\d/.test(r[1])){if(parseInt(r[1],10)-1>1048575)return null}else if(d(r[1])>16383)return null;return l}}const P=[D("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),D("operator",/^(<=|>=|<>|[-+/*^%&<>=]|[{},;]|[()]|@|:|!|#)/),D("func",/^[A-Z_]+[A-Z\d_.]*(?=\()/i),D("bool",/^(TRUE|FALSE)\b/i),D("newline",/^\n+/),D("whitespace",/^[ \f\r\t\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]+/),D("string",/^"(?:""|[^"])*("|$)/),D("context_quote",C),D("context",A),j,D("number",/^(?:\d+(\.\d+)?(?:[eE][+-]?\d+)?|\d+)/),D("range_named",z)],K=[function(e,n){return n.r1c1?"!"===e[0]?{type:"operator",value:e[0]}:null:"!"===e[0]||":"===e[0]?{type:"operator",value:e[0]}:null},D("context_quote",C),D("context",A),j,D("range_named",z)],V={};function Y(e,n){if(e.length){const t=e[0];n[t]=n[t]||{},Y(e.slice(1),n[t])}else n.$=!0}[[e,":",e],[e],["range_beam"],["range_ternary"],["context","!",e,":",e],["context","!",e],["context","!","range_beam"],["context","!","range_ternary"],["context_quote","!",e,":",e],["context_quote","!",e],["context_quote","!","range_beam"],["context_quote","!","range_ternary"],["range_named"],["context","!","range_named"],["context_quote","!","range_named"]].forEach((e=>Y(e.concat().reverse(),V)));const H=function(e,n,t){let r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:0;const l=e[t-r];if(l){const o="operator"===l.type?l.value:l.type;if(o in n)return H(e,n[o],t,r+1)}return n.$?r:0};function Q(e){const n=[];for(let t=e.length-1;t>=0;t--){let r=e[t];const l=H(e,V,t);if(l){const n=e.slice(t-l+1,t+1);r={...r},r.value=n.map((e=>e.value)).join(""),r.range&&n[0].range&&(r.range[0]=n[0].range[0]),t-=l-1}n.unshift(r)}return n}const J=(e,n)=>e&&e.type===n,ee={emitRanges:!1,mergeRanges:!0,allowTernary:!1,negativeNumbers:!0,r1c1:!1},ne=e=>"range_named"===e.type||"func"===e.type,te=e=>!J(e,"operator")||"%"===e.value||"}"===e.value||")"===e.value||"#"===e.value;function re(e,t){let r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};const l=Object.assign({},ee,r),{emitRanges:o,mergeRanges:a,negativeNumbers:u}=l,c=[];let i=0,g=null,f=null,s=null;const p=e=>{const t=e.type===n,r=s&&s.type===n;s&&(t&&r||t&&ne(s)||r&&ne(e))?(s.value+=e.value,s.type=n,o&&(s.range[1]=e.range[1])):(c.push(e),s=e,"whitespace"!==e.type&&"newline"!==e.type&&(f=g,g=e))};if(/^=/.test(e)){i++,p({type:"fx_prefix",value:"=",...o?{range:[0,1]}:{}})}for(;i<e.length;){const r=i,a=e.slice(i);let $="",m="";for(let e=0;e<t.length;e++){const n=t[e](a,l);if(n){$=n.type,m=n.value,i+=m.length;break}}$||($=n,m=e[i],i++);const d={type:$,value:m,...o?{range:[r,i]}:{}};if("string"===$){const e=m.length;if('""'===m);else if('"'===m||'"'!==m[e-1])d.unterminated=!0;else if('""'!==m&&'"'===m[e-2]){let n=e-1;for(;'"'===m[n];)n--;!(n+1)^(e-n+1)%2==0&&(d.unterminated=!0)}}if(u&&"number"===$){const e=s;if(e&&J(e,"operator")&&"-"===e.value&&(!f||J(f,"fx_prefix")||!te(f))){const e=c.pop();d.value="-"+m,o&&(d.range[0]=e.range[0]),g=f,s=c[c.length-1]}}p(d)}return a?Q(c):c}function le(e){let n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return re(e,P,n)}function oe(){let e=1;return()=>"fxg"+e++}function ae(e,n){return null==e&&null==n||e===n}function ue(e,n){return!e&&!n||String(e).toLowerCase()===String(n).toLowerCase()}function ce(e,n){return(!e.name&&!n.name||e.name===n.name)&&(!!(!e.range&&!n.range||ae(e.range.top,n.range.top)&&ae(e.range.bottom,n.range.bottom)&&ae(e.range.left,n.range.left)&&ae(e.range.right,n.range.right))&&!(!ue(e.context[0],n.context[0])||!ue(e.context[1],n.context[1])))}function ie(e,n){return n?String(e+1):e?"["+e+"]":""}function ge(e){const{r0:n,c0:t,r1:r,c1:l,$c0:o,$c1:a,$r0:u,$r1:c}=e,i=null==n,g=null==r,f=null==t,s=null==l;if(0===n&&r>=1048575||i&&g){const e=ie(t,o),n=ie(l,a);return"C"+(e===n?e:e+":C"+n)}if(0===t&&l>=16383||f&&s){const e=ie(n,u),t=ie(r,c);return"R"+(e===t?e:e+":R"+t)}const p=ie(n,u),$=ie(r,c),m=ie(t,o),d=ie(l,a);return i||g||f||s?(i?"":"R"+p)+(f?"":"C"+m)+":"+(g?"":"R"+$)+(s?"":"C"+d):p!==$||m!==d?"R"+p+"C"+m+":R"+$+"C"+d:"R"+p+"C"+m}function fe(e){let n=null,t=null,r=null,l=null;const o=/^R(?:\[([+-]?\d+)\]|(\d+))?/.exec(e);o&&(o[1]?(n=parseInt(o[1],10),r=!1):o[2]?(n=parseInt(o[2],10)-1,r=!0):(n=0,r=!1),e=e.slice(o[0].length));const a=/^C(?:\[([+-]?\d+)\]|(\d+))?/.exec(e);return a&&(a[1]?(t=parseInt(a[1],10),l=!1):a[2]?(t=parseInt(a[2],10)-1,l=!0):(t=0,l=!1),e=e.slice(a[0].length)),!o&&!a||e.length?null:[n,t,r,l]}function se(e){let n=null;const[t,r]=e.split(":",2),l=fe(t);if(l){const[e,t,o,a]=l;if(!r)return null!=e&&null==t?{r0:e,c0:null,r1:e,c1:null,$r0:o,$c0:!1,$r1:o,$c1:!1}:null==e&&null!=t?{r0:null,c0:t,r1:null,c1:t,$r0:!1,$c0:a,$r1:!1,$c1:a}:{r0:e||0,c0:t||0,r1:e||0,c1:t||0,$r0:o||!1,$c0:a||!1,$r1:o||!1,$c1:a||!1};{const l=fe(r);if(!l)return null;{n={};const[r,u,c,i]=l;null!=e&&null!=r?(n.r0=o===c?Math.min(e,r):e,n.$r0=o,n.r1=o===c?Math.max(e,r):r,n.$r1=c):null!=e&&null==r?(n.r0=e,n.$r0=o,n.r1=null,n.$r1=o):null==e&&null!=r?(n.r0=r,n.$r0=c,n.r1=null,n.$r1=c):null==e&&null==r&&(n.r0=null,n.$r0=!1,n.r1=null,n.$r1=!1),null!=t&&null!=u?(n.c0=a===i?Math.min(t,u):t,n.$c0=a,n.c1=a===i?Math.max(t,u):u,n.$c1=i):null!=t&&null==u?(n.c0=t,n.$c0=a,n.c1=null,n.$c1=a):null==t&&null!=u?(n.c0=u,n.$c0=i,n.c1=null,n.$c1=i):null==t&&null==u&&(n.c0=null,n.$c0=!1,n.c1=null,n.$c1=!1)}}}return n}function pe(e){let{allowNamed:n=!0,allowTernary:t=!1}=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const r=p(e,{allowNamed:n,allowTernary:t,r1c1:!0});if(r&&(r.r0||r.name)){const e=r.r1?se(r.r0+":"+r.r1):se(r.r0);return r.name||e?(r.range=e,delete r.r0,delete r.r1,r):null}return null}function $e(e){return m(e)+(e.name?e.name:ge(e.range))}var me={to:ge,from:se,parse:pe,stringify:$e};function de(n){return!!n&&(n.type===e||"range_beam"===n.type||"range_ternary"===n.type)}const he=(e,n,t)=>null==n?null:e?n:n-t,xe={emitRanges:!1,mergeRanges:!1,allowTernary:!0,r1c1:!1};function ye(e,n,t,r){let l=e;return null==l||n||(l=t+e,l<0&&(l=r+l+1),l>r&&(l-=r+1)),l}const ve={OPERATOR:"operator",BOOLEAN:"bool",ERROR:"error",NUMBER:"number",FUNCTION:"func",NEWLINE:"newline",WHITESPACE:"whitespace",STRING:"string",CONTEXT:"context",CONTEXT_QUOTE:"context_quote",RANGE:e,RANGE_BEAM:"range_beam",RANGE_TERNARY:"range_ternary",RANGE_NAMED:"range_named",FX_PREFIX:"fx_prefix",UNKNOWN:n};exports.MAX_COLS=16383,exports.MAX_ROWS=1048575,exports.a1=N,exports.addMeta=function(t){let{sheetName:r="",workbookName:l=""}=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const o=[];let a=null;const u=oe(),c=[],i=()=>o.length+(a?1:0);return t.forEach(((t,g)=>{if(t.index=g,t.depth=i(),"("===t.value)o.push(t),t.depth=i();else if(")"===t.value){const e=o.pop();if(e){const n=u();t.groupId=n,t.depth=e.depth,e.groupId=n}else t.error=!0}else if("{"===t.value)a?t.error=!0:(a=t,t.depth=i());else if("}"===t.value){if(a){const e=u();t.groupId=e,t.depth=a.depth,a.groupId=e}else t.error=!0;a=null}else if(t.type===e||"range_beam"===t.type||"range_ternary"===t.type){const e=b(t.value,{allowNamed:!1,allowTernary:!0});if(e&&e.range){if(e.source=t.value,e.context.length){if(1===e.context.length){const n=e.context[0];e.context=n===r||n===l?[l,r]:[l,n]}}else e.context=[l,r];const n=c.find((n=>ce(n,e)));n?t.groupId=n.groupId:(e.groupId=u(),t.groupId=e.groupId,c.push(e))}}else t.type===n&&(t.error=!0)})),t},exports.fixRanges=function e(n){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{addBounds:!1};if("string"==typeof n)return e(le(n,t),t).map((e=>e.value)).join("");if(!Array.isArray(n))throw new Error("fixRanges expects an array of tokens");const{addBounds:r,r1c1:l}=t;if(l)throw new Error("fixRanges does not have an R1C1 mode");return n.map((e=>{if(de(e)){const n=b(e.value,t),l=n.range;r&&w(l);const o={...e};return o.value=E(n),o.range&&(o.range=l),o}return e}))},exports.isRange=de,exports.isReference=function(n){return!!n&&(n.type===e||"range_beam"===n.type||"range_ternary"===n.type||"range_named"===n.type)},exports.mergeRanges=Q,exports.rc=me,exports.tokenTypes=ve,exports.tokenize=le,exports.translateToA1=function(e,n){const t=_(n),r="string"==typeof e,l=r?le(e,{emitRanges:!1,mergeRanges:!1,allowTernary:!0,r1c1:!0}):e;let o=0;return l.forEach((e=>{if(de(e)){const n=e.value,r=pe(n,{allowTernary:!0}),l=r.range,a={},u=ye(l.r0,l.$r0,t.top,1048575),c=ye(l.r1,l.$r1,t.top,1048575);u>c?(a.top=c,a.$top=l.$r1,a.bottom=u,a.$bottom=l.$r0):(a.top=u,a.$top=l.$r0,a.bottom=c,a.$bottom=l.$r1);const i=ye(l.c0,l.$c0,t.left,16383),g=ye(l.c1,l.$c1,t.left,16383);i>g?(a.left=g,a.$left=l.$c1,a.right=i,a.$right=l.$c0):(a.left=i,a.$left=l.$c0,a.right=g,a.$right=l.$c1),r.range=a,e.value=E(r),e.range&&(e.range[0]+=o,o+=e.value.length-n.length,e.range[1]+=o)}else o&&e.range&&(e.range[0]+=o,e.range[1]+=o)})),r?l.map((e=>e.value)).join(""):l},exports.translateToRC=function(e,n){const{top:t,left:r}=_(n),l="string"==typeof e,o=l?le(e,xe):e;let a=0;return o.forEach((e=>{if(de(e)){const n=e.value,l=b(n,{allowTernary:!0}),o=l.range,u={};u.r0=he(o.$top,o.top,t),u.r1=he(o.$bottom,o.bottom,t),u.c0=he(o.$left,o.left,r),u.c1=he(o.$right,o.right,r),u.$r0=o.$top,u.$r1=o.$bottom,u.$c0=o.$left,u.$c1=o.$right,l.range=u,e.value=$e(l),e.range&&(e.range[0]+=a,a+=e.value.length-n.length,e.range[1]+=a)}else a&&e.range&&(e.range[0]+=a,e.range[1]+=a)})),l?o.map((e=>e.value)).join(""):o};
2
2
  //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnguanMiLCJzb3VyY2VzIjpbXSwic291cmNlc0NvbnRlbnQiOltdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIn0=
package/lib/lexer.js CHANGED
@@ -138,7 +138,7 @@ export function getTokens (fx, tokenHandlers, options = {}) {
138
138
  if (
139
139
  !tail1 ||
140
140
  isType(tail1, FX_PREFIX) ||
141
- !causesBinaryMinus(tail1, OPERATOR)
141
+ !causesBinaryMinus(tail1)
142
142
  ) {
143
143
  const minus = tokens.pop();
144
144
  token.value = '-' + tokenValue;
package/lib/lexer.spec.js CHANGED
@@ -239,6 +239,18 @@ test('tokenize functions', t => {
239
239
  { type: OPERATOR, value: '(' },
240
240
  { type: OPERATOR, value: ')' }
241
241
  ]);
242
+ t.isTokens('=TRUE()', [
243
+ { type: FX_PREFIX, value: '=' },
244
+ { type: FUNCTION, value: 'TRUE' },
245
+ { type: OPERATOR, value: '(' },
246
+ { type: OPERATOR, value: ')' }
247
+ ]);
248
+ t.isTokens('=FALSE()', [
249
+ { type: FX_PREFIX, value: '=' },
250
+ { type: FUNCTION, value: 'FALSE' },
251
+ { type: OPERATOR, value: '(' },
252
+ { type: OPERATOR, value: ')' }
253
+ ]);
242
254
  t.isTokens('=@SUM(1)', [
243
255
  { type: FX_PREFIX, value: '=' },
244
256
  { type: OPERATOR, value: '@' },
@@ -1270,6 +1282,18 @@ test('tokenize errors', t => {
1270
1282
  { type: FX_PREFIX, value: '=' },
1271
1283
  { type: ERROR, value: '#ERROR!' }
1272
1284
  ]);
1285
+ t.isTokens('=#CONNECT!', [
1286
+ { type: FX_PREFIX, value: '=' },
1287
+ { type: ERROR, value: '#CONNECT!' }
1288
+ ]);
1289
+ t.isTokens('=#BLOCKED!', [
1290
+ { type: FX_PREFIX, value: '=' },
1291
+ { type: ERROR, value: '#BLOCKED!' }
1292
+ ]);
1293
+ t.isTokens('=#EXTERNAL!', [
1294
+ { type: FX_PREFIX, value: '=' },
1295
+ { type: ERROR, value: '#EXTERNAL!' }
1296
+ ]);
1273
1297
 
1274
1298
  // TODO: is this really what should happen?
1275
1299
  t.isTokens('=#NONSENSE!', [
package/lib/lexerParts.js CHANGED
@@ -18,7 +18,7 @@ import {
18
18
  } from './constants.js';
19
19
  import { fromCol } from './a1.js';
20
20
 
21
- const re_ERROR = /^#(NAME\?|FIELD!|CALC!|VALUE!|REF!|DIV\/0!|NULL!|NUM!|N\/A|GETTING_DATA\b|SPILL!|UNKNOWN!|FIELD\b|CALC\b|SYNTAX\?|ERROR!)/i;
21
+ const re_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;
22
22
  const re_OPERATOR = /^(<=|>=|<>|[-+/*^%&<>=]|[{},;]|[()]|@|:|!|#)/;
23
23
  const re_BOOLEAN = /^(TRUE|FALSE)\b/i;
24
24
  const re_FUNCTION = /^[A-Z_]+[A-Z\d_.]*(?=\()/i;
@@ -132,8 +132,8 @@ function lexRefOp (s, opts) {
132
132
  export const lexers = [
133
133
  makeHandler(ERROR, re_ERROR),
134
134
  makeHandler(OPERATOR, re_OPERATOR),
135
- makeHandler(BOOLEAN, re_BOOLEAN),
136
135
  makeHandler(FUNCTION, re_FUNCTION),
136
+ makeHandler(BOOLEAN, re_BOOLEAN),
137
137
  makeHandler(NEWLINE, re_NEWLINE),
138
138
  makeHandler(WHITESPACE, re_WHITESPACE),
139
139
  makeHandler(STRING, re_STRING),
@@ -1,8 +1,11 @@
1
1
  import { test, Test } from 'tape';
2
2
  import { translateToA1 } from './translate.js';
3
+ import { tokenize } from './lexer.js';
4
+ import { addMeta } from './addMeta.js';
5
+ import { FUNCTION, FX_PREFIX, OPERATOR, RANGE, RANGE_BEAM } from './constants.js';
3
6
 
4
- Test.prototype.isR2A = function isTokens (expr, anchor, result, debug) {
5
- this.is(translateToA1(expr, anchor, debug), result, expr);
7
+ Test.prototype.isR2A = function isTokens (expr, anchor, result) {
8
+ this.is(translateToA1(expr, anchor), result, expr);
6
9
  };
7
10
 
8
11
  test('translate absolute cells from RC to A1', t => {
@@ -124,3 +127,33 @@ test('translate involved formula from RC to A1', t => {
124
127
  '=SUM(IF(E10,$E$2,$E$3),Sheet1!$2:$2*Sheet2!B:B)');
125
128
  t.end();
126
129
  });
130
+
131
+ test('translate works with merged ranges', t => {
132
+ // This tests that:
133
+ // - Translate works with ranges that have context attached
134
+ // - If input is a tokenlist, output is also a tokenlist
135
+ // - If tokens have ranges, those ranges are adjusted to new token lengths
136
+ // - Properties added by addMeta are preserved
137
+ const expr = '=SUM(IF(RC[1],R2C5,R3C5),Sheet1!R2*Sheet2!C[-2])';
138
+ const tokens = addMeta(tokenize(expr, { emitRanges: true, r1c1: true }));
139
+ const expected = [
140
+ { type: FX_PREFIX, value: '=', range: [ 0, 1 ], index: 0, depth: 0 },
141
+ { type: FUNCTION, value: 'SUM', range: [ 1, 4 ], index: 1, depth: 0 },
142
+ { type: OPERATOR, value: '(', range: [ 4, 5 ], index: 2, depth: 1, groupId: 'fxg3' },
143
+ { type: FUNCTION, value: 'IF', range: [ 5, 7 ], index: 3, depth: 1 },
144
+ { type: OPERATOR, value: '(', range: [ 7, 8 ], index: 4, depth: 2, groupId: 'fxg1' },
145
+ { type: RANGE, value: 'E10', range: [ 8, 11 ], index: 5, depth: 2 },
146
+ { type: OPERATOR, value: ',', range: [ 11, 12 ], index: 6, depth: 2 },
147
+ { type: RANGE, value: '$E$2', range: [ 12, 16 ], index: 7, depth: 2 },
148
+ { type: OPERATOR, value: ',', range: [ 16, 17 ], index: 8, depth: 2 },
149
+ { type: RANGE, value: '$E$3', range: [ 17, 21 ], index: 9, depth: 2 },
150
+ { type: OPERATOR, value: ')', range: [ 21, 22 ], index: 10, depth: 2, groupId: 'fxg1' },
151
+ { type: OPERATOR, value: ',', range: [ 22, 23 ], index: 11, depth: 1 },
152
+ { type: RANGE_BEAM, value: 'Sheet1!$2:$2', range: [ 23, 35 ], index: 12, depth: 1, groupId: 'fxg2' },
153
+ { type: OPERATOR, value: '*', range: [ 35, 36 ], index: 13, depth: 1 },
154
+ { type: RANGE_BEAM, value: 'Sheet2!B:B', range: [ 36, 46 ], index: 14, depth: 1 },
155
+ { type: OPERATOR, value: ')', range: [ 46, 47 ], index: 15, depth: 1, groupId: 'fxg3' }
156
+ ];
157
+ t.deepEqual(translateToA1(tokens, 'D10'), expected, expr);
158
+ t.end();
159
+ });
@@ -1,5 +1,8 @@
1
1
  import { test, Test } from 'tape';
2
2
  import { translateToRC } from './translate.js';
3
+ import { tokenize } from './lexer.js';
4
+ import { addMeta } from './addMeta.js';
5
+ import { FUNCTION, FX_PREFIX, OPERATOR, RANGE, RANGE_BEAM } from './constants.js';
3
6
 
4
7
  Test.prototype.isA2R = function isTokens (expr, anchor, result) {
5
8
  this.is(translateToRC(expr, anchor), result, expr);
@@ -117,3 +120,33 @@ test('translate involved formula from A1 to RC', t => {
117
120
  '=SUM(IF(RC[1],R2C5,R3C5),Sheet1!R2*Sheet2!C[-2])');
118
121
  t.end();
119
122
  });
123
+
124
+ test('translate works with merged ranges', t => {
125
+ // This tests that:
126
+ // - Translate works with ranges that have context attached
127
+ // - If input is a tokenlist, output is also a tokenlist
128
+ // - If tokens have ranges, those ranges are adjusted to new token lengths
129
+ // - Properties added by addMeta are preserved
130
+ const expr = '=SUM(IF(E10,$E$2,$E$3),Sheet1!$2:$2*Sheet2!B:B)';
131
+ const tokens = addMeta(tokenize(expr, { emitRanges: true }));
132
+ const expected = [
133
+ { type: FX_PREFIX, value: '=', range: [ 0, 1 ], index: 0, depth: 0 },
134
+ { type: FUNCTION, value: 'SUM', range: [ 1, 4 ], index: 1, depth: 0 },
135
+ { type: OPERATOR, value: '(', range: [ 4, 5 ], index: 2, depth: 1, groupId: 'fxg7' },
136
+ { type: FUNCTION, value: 'IF', range: [ 5, 7 ], index: 3, depth: 1 },
137
+ { type: OPERATOR, value: '(', range: [ 7, 8 ], index: 4, depth: 2, groupId: 'fxg4' },
138
+ { type: RANGE, value: 'RC[1]', range: [ 8, 13 ], index: 5, depth: 2, groupId: 'fxg1' },
139
+ { type: OPERATOR, value: ',', range: [ 13, 14 ], index: 6, depth: 2 },
140
+ { type: RANGE, value: 'R2C5', range: [ 14, 18 ], index: 7, depth: 2, groupId: 'fxg2' },
141
+ { type: OPERATOR, value: ',', range: [ 18, 19 ], index: 8, depth: 2 },
142
+ { type: RANGE, value: 'R3C5', range: [ 19, 23 ], index: 9, depth: 2, groupId: 'fxg3' },
143
+ { type: OPERATOR, value: ')', range: [ 23, 24 ], index: 10, depth: 2, groupId: 'fxg4' },
144
+ { type: OPERATOR, value: ',', range: [ 24, 25 ], index: 11, depth: 1 },
145
+ { type: RANGE_BEAM, value: 'Sheet1!R2', range: [ 25, 34 ], index: 12, depth: 1, groupId: 'fxg5' },
146
+ { type: OPERATOR, value: '*', range: [ 34, 35 ], index: 13, depth: 1 },
147
+ { type: RANGE_BEAM, value: 'Sheet2!C[-2]', range: [ 35, 47 ], index: 14, depth: 1, groupId: 'fxg6' },
148
+ { type: OPERATOR, value: ')', range: [ 47, 48 ], index: 15, depth: 1, groupId: 'fxg7' }
149
+ ];
150
+ t.deepEqual(translateToRC(tokens, 'D10'), expected, expr);
151
+ t.end();
152
+ });
package/lib/translate.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { MAX_ROWS, MAX_COLS } from './constants.js';
2
- import { fromA1, toA1 } from './a1.js';
3
- import { fromRC, toRC } from './rc.js';
2
+ import { fromA1, parseA1Ref, stringifyA1Ref } from './a1.js';
3
+ import { parseRCRef, stringifyRCRef } from './rc.js';
4
4
  import { tokenize } from './lexer.js';
5
5
  import { isRange } from './isType.js';
6
6
 
@@ -11,27 +11,48 @@ const calc = (abs, vX, aX) => {
11
11
  return abs ? vX : vX - aX;
12
12
  };
13
13
 
14
+ const settings = {
15
+ emitRanges: false,
16
+ mergeRanges: false,
17
+ allowTernary: true,
18
+ r1c1: false
19
+ };
20
+
14
21
  export function translateToRC (fx, anchorCell) {
15
22
  const { top, left } = fromA1(anchorCell);
16
23
  const isString = typeof fx === 'string';
17
24
 
18
25
  const tokens = isString
19
- ? tokenize(fx, { emitRanges: false, mergeRanges: false, allowTernary: true, r1c2: false })
26
+ ? tokenize(fx, settings)
20
27
  : fx;
21
28
 
29
+ let offsetSkew = 0;
22
30
  tokens.forEach(token => {
23
31
  if (isRange(token)) {
32
+ const tokenValue = token.value;
33
+ const ref = parseA1Ref(tokenValue, { allowTernary: true });
34
+ const d = ref.range;
24
35
  const range = {};
25
- const d = fromA1(token.value);
26
36
  range.r0 = calc(d.$top, d.top, top);
27
- range.$r0 = d.$top;
28
37
  range.r1 = calc(d.$bottom, d.bottom, top);
29
- range.$r1 = d.$bottom;
30
38
  range.c0 = calc(d.$left, d.left, left);
31
- range.$c0 = d.$left;
32
39
  range.c1 = calc(d.$right, d.right, left);
40
+ range.$r0 = d.$top;
41
+ range.$r1 = d.$bottom;
42
+ range.$c0 = d.$left;
33
43
  range.$c1 = d.$right;
34
- token.value = toRC(range);
44
+ ref.range = range;
45
+ token.value = stringifyRCRef(ref);
46
+ // if token includes offsets, those offsets are now likely wrong!
47
+ if (token.range) {
48
+ token.range[0] += offsetSkew;
49
+ offsetSkew += token.value.length - tokenValue.length;
50
+ token.range[1] += offsetSkew;
51
+ }
52
+ }
53
+ else if (offsetSkew && token.range) {
54
+ token.range[0] += offsetSkew;
55
+ token.range[1] += offsetSkew;
35
56
  }
36
57
  });
37
58
 
@@ -67,10 +88,13 @@ export function translateToA1 (fx, anchorCell) {
67
88
  ? tokenize(fx, { emitRanges: false, mergeRanges: false, allowTernary: true, r1c1: true })
68
89
  : fx;
69
90
 
91
+ let offsetSkew = 0;
70
92
  tokens.forEach(token => {
71
93
  if (isRange(token)) {
94
+ const tokenValue = token.value;
95
+ const ref = parseRCRef(tokenValue, { allowTernary: true });
96
+ const d = ref.range;
72
97
  const range = {};
73
- const d = fromRC(token.value);
74
98
  const r0 = toFixed(d.r0, d.$r0, anchor.top, MAX_ROWS);
75
99
  const r1 = toFixed(d.r1, d.$r1, anchor.top, MAX_ROWS);
76
100
  if (r0 > r1) {
@@ -99,7 +123,18 @@ export function translateToA1 (fx, anchorCell) {
99
123
  range.right = c1;
100
124
  range.$right = d.$c1;
101
125
  }
102
- token.value = toA1(range);
126
+ ref.range = range;
127
+ token.value = stringifyA1Ref(ref);
128
+ // if token includes offsets, those offsets are now likely wrong!
129
+ if (token.range) {
130
+ token.range[0] += offsetSkew;
131
+ offsetSkew += token.value.length - tokenValue.length;
132
+ token.range[1] += offsetSkew;
133
+ }
134
+ }
135
+ else if (offsetSkew && token.range) {
136
+ token.range[0] += offsetSkew;
137
+ token.range[1] += offsetSkew;
103
138
  }
104
139
  });
105
140
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@borgar/fx",
3
- "version": "3.0.0-rc.0",
3
+ "version": "3.1.0",
4
4
  "description": "Utilities for working with Excel formulas",
5
5
  "main": "dist/fx.js",
6
6
  "module": "lib/index.js",