@borgar/fx 3.0.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 +9 -9
- package/dist/fx.js +1 -1
- package/lib/lexer.js +1 -1
- package/lib/lexer.spec.js +24 -0
- package/lib/lexerParts.js +2 -2
- package/lib/translate-toA1.spec.js +35 -2
- package/lib/translate-toRC.spec.js +33 -0
- package/lib/translate.js +45 -10
- package/package.json +1 -1
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**(
|
|
257
|
+
#### <a name="a1.to" href="#a1.to">#</a> **.to**( _rangeObject_ )
|
|
258
258
|
|
|
259
|
-
|
|
259
|
+
Stringify a range object ([see above](#a1.parse)) into A1 syntax.
|
|
260
260
|
|
|
261
|
-
#### <a name="a1.from" href="#a1.from">#</a> **.from**(
|
|
261
|
+
#### <a name="a1.from" href="#a1.from">#</a> **.from**( _rangeString_ )
|
|
262
262
|
|
|
263
|
-
|
|
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**(
|
|
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
|
|
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
|
|
5
|
-
this.is(translateToA1(expr, anchor
|
|
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,
|
|
3
|
-
import {
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|