@borgar/fx 4.9.0 → 4.10.1
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.d.ts +2 -0
- package/dist/fx.js +1 -1
- package/docs/API.md +11 -10
- package/lib/a1.js +58 -23
- package/lib/a1.spec.js +75 -13
- package/lib/addTokenMeta.js +1 -1
- package/lib/addTokenMeta.spec.js +12 -0
- package/lib/constants.js +1 -0
- package/lib/extraTypes.js +1 -0
- package/lib/fixRanges.spec.js +3 -0
- package/lib/lexer.js +24 -2
- package/lib/lexer.spec.js +119 -0
- package/lib/lexerParts.js +18 -11
- package/lib/mergeRefTokens.js +9 -0
- package/lib/mergeRefTokens.spec.js +3 -0
- package/lib/parseRef.js +5 -3
- package/lib/parser.js +2 -1
- package/lib/parser.spec.js +13 -0
- package/lib/rc.js +28 -16
- package/lib/rc.spec.js +52 -13
- package/lib/sr.spec.js +1 -1
- package/lib/stringifyPrefix.js +3 -3
- package/lib/translate-toA1.spec.js +13 -0
- package/lib/translate-toRC.spec.js +13 -0
- package/lib/translate.js +6 -0
- package/package.json +1 -1
package/dist/fx.d.ts
CHANGED
|
@@ -705,6 +705,8 @@ export declare type RangeA1 = {
|
|
|
705
705
|
right?: (number | null);
|
|
706
706
|
/** Top row of the range */
|
|
707
707
|
top?: (number | null);
|
|
708
|
+
/** Should empty rows and columns at the top/left or bottom/right be discarded when range is read? */
|
|
709
|
+
trim?: ("head" | "tail" | "both");
|
|
708
710
|
};
|
|
709
711
|
|
|
710
712
|
/** A range in R1C1 style coordinates. */
|
package/dist/fx.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";const e="operator",t="error",n="range_beam",l="range_ternary",r="range_named",o="structured",s="unknown",u="UnaryExpression",i="BinaryExpression",c="ReferenceIdentifier",a="CallExpression",f="LetExpression";function p(e){let t=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=!1,l="";const r=[],o=()=>{l&&r.push(t?l:{value:l,braced:n}),l=""};for(let t=0;t<e.length;t++){const r=e[t];"["===r?(o(),n=!0):"]"===r?(o(),n=!1):l+=r}return o(),r}function h(e){return{context:p(e,!0)}}function g(e){const t={},n=p(e);if(n.length>1)t.workbookName=n[n.length-2].value,t.sheetName=n[n.length-1].value;else if(1===n.length){const e=n[0];e.braced?t.workbookName=e.value:t.sheetName=e.value}return t}const d=e=>e&&":"===e.value&&{},x=e=>e&&"range"===e.type&&{r0:e.value},y=e=>e&&e.type===l&&{r0:e.value},m=e=>e&&"range"===e.type&&{r1:e.value},v=t=>t&&t.type===e&&"!"===t.value&&{},$=e=>e&&e.type===n&&{r0:e.value},w=e=>e&&e.type===o&&{struct:e.value},E=(e,t)=>{const n=t.xlsx?g:h;return e&&"context"===e.type?n(e.value):e&&"context_quote"===e.type?n(e.value.slice(1,-1).replace(/''/g,"'")):void 0},R=e=>e&&e.type===r&&{name:e.value},N=[[y],[x,d,m],[x],[$],[E,v,y],[E,v,x,d,m],[E,v,x],[E,v,$]],b=N.concat([[R],[E,v,R],[w],[R,w],[E,v,R,w]]);function A(e,t){const n={withLocation:!1,mergeRefs:!1,allowTernary:!1,allowNamed:!0,r1c1:!1,xlsx:!1,...t},l=Me(e,Ce,n),r=n.xlsx?{workbookName:"",sheetName:"",r0:"",r1:"",name:""}:{context:[],r0:"",r1:"",name:""};l.length&&"fx_prefix"===l[0].type&&l.shift();const o=n.allowNamed?b:N;for(let e=0;e<o.length;e++){const t={...r};if(o[e].length===l.length){const r=o[e].every(((e,r)=>{const o=e(l[r],n);return Object.assign(t,o),o}));if(r)return t}}return null}const C=/[^0-9A-Za-z._¡¤§¨ª\u00ad¯-\uffff]/;function T(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+=C.test(o),l++}}return n&&(t="'"+t.replace(/'/g,"''")+"'"),t?t+"!":t}function L(e){let t="",n=0;const{workbookName:l,sheetName:r}=e;return l&&(t+="["+l+"]",n+=C.test(l)),r&&(t+=r,n+=C.test(r)),n&&(t="'"+t.replace(/'/g,"''")+"'"),t?t+"!":t}const I=(e,t,n)=>Math.min(Math.max(t,e),n),k=(e,t)=>(t?"$":"")+F(e),O=(e,t)=>(t?"$":"")+String(e+1),_=String.fromCharCode;function U(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 F(e){return(e>=702?_(((e-702)/676-0)%26+65):"")+(e>=26?_((e/26-1)%26+65):"")+_(e%26+65)}function S(e){let{top:t,left:n,bottom:l,right:r}=e;const{$left:o,$right:s,$top:u,$bottom:i}=e,c=null==n,a=null==r,f=null==t,p=null==l;t=I(0,0|t,1048575),n=I(0,0|n,16383),!c&&!f&&a&&p?(l=t,r=n):(l=I(0,0|l,1048575),r=I(0,0|r,16383));if(0===t&&l>=1048575&&!c&&!a&&(!(o&&!c||s&&!a)||n===r)||f&&p)return k(n,o)+":"+k(r,s);return 0===n&&r>=16383&&!f&&!p&&(!(u&&!f||i&&!p)||t===l)||c&&a?O(t,u)+":"+O(l,i):c||f||a||!p?c||!f||a||p?c||f||!a||p?!c||f||a||p?r!==n||l!==t||s!==o||i!==u?k(n,o)+O(t,u)+":"+k(r,s)+O(l,i):k(n,o)+O(t,u):k(r,s)+O(t,u)+":"+O(l,i):k(n,o)+O(t,u)+":"+O(l,i):k(n,o)+O(l,i)+":"+k(r,s):k(n,o)+O(t,u)+":"+k(r,s)}function M(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]?U(t[2]):null,!!t[3],!!t[1]]:null;var n}function D(e){let t=null,n=null,l=null,r=null,o=!1,s=!1,u=!1,i=!1;const[c,a,f]=e.split(":");if(f)return null;const p=M(c),h=a?M(a):null;if(!p||a&&!h)return null;if(null!=p[0]&&null!=p[1]?[t,n,o,s]=p:null==p[0]&&null!=p[1]?[,n,,s]=p:null!=p[0]&&null==p[1]&&([t,,o]=p),a)null!=h[0]&&null!=h[1]?[l,r,u,i]=h:null==h[0]&&null!=h[1]?[,r,,i]=h:null!=h[0]&&null==h[1]&&([l,,u]=h);else{if(null==t||null==n)return null;l=t,r=n,u=o,i=s}return null!=r&&(null==n||null!=n&&r<n)&&([n,r,s,i]=[r,n,i,s]),null!=l&&(null==t||null!=t&&l<t)&&([t,l,o,u]=[l,t,u,o]),{top:t,left:n,bottom:l,right:r,$top:o,$left:s,$bottom:u,$right:i}}function z(e){let{allowNamed:t=!0,allowTernary:n=!1,xlsx:l=!1}=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const r=A(e,{allowNamed:t,allowTernary:n,xlsx:l,r1c1:!1});if(r&&(r.r0||r.name)){let e=null;return r.r0&&(e=D(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 j(e){let{xlsx:t=!1}=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const n=t?L(e):T(e);return n+(e.name?e.name:S(e.range))}function B(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 Z=/^\[('['#@[\]]|[^'#@[\]])+\]/i,q=/^([^#@[\]:]+)/i,P={headers:1,data:2,totals:4,all:8,"this row":16,"@":16},X=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:X(),1:X("headers"),2:X("data"),4:X("totals"),8:X("all"),16:X("this row"),3:X("headers","data"),6:X("data","totals")},H=function(e){let t=!(arguments.length>1&&void 0!==arguments[1])||arguments[1],n=Z.exec(e);if(n){const e=n[0].slice(1,-1).replace(/'(['#@[\]])/g,"$1");return[n[0],e]}return t&&(n=q.exec(e),n)?[n[0],n[0]]:null};function Y(e){const t=[];let n,l,r=0,o=e,s=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,!P[e])return null;s|=P[e]}else if(l=H(o,!1))r+=l[0].length,t.push(l[1]);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(!P[e])return null;s|=P[e],o=o.slice(n[0].length),r+=n[0].length,l=!!n[2]}if(l&&(n=/^@/.exec(o))&&(s|=P["@"],o=o.slice(1),r+=1,l="]"!==o[0]),!(s in W))return null;const u=l?H(e.slice(r)):null;if(u){if(r+=u[0].length,t.push(u[1]),o=e.slice(r),":"===o[0]){o=o.slice(1),r++;const e=H(o);if(!e)return null;r+=e[0].length,t.push(e[1])}l=!1}for(;" "===e[r];)r++;if(l||"]"!==e[r])return null;r++}const u=W[s];return{columns:t,sections:u?u.concat():u,length:r,token:e.slice(0,r)}}function G(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{xlsx:!1};const n=A(e,t);if(n&&n.struct){const e=Y(n.struct);if(e&&e.length===n.struct.length)return t.xlsx?{workbookName:n.workbookName,sheetName:n.sheetName,table:n.name,columns:e.columns,sections:e.sections}:{context:n.context,table:n.name,columns:e.columns,sections:e.sections}}return null}function K(e){return e.replace(/([[\]#'@])/g,"'$1")}function V(e){return!/^[a-zA-Z0-9\u00a1-\uffff]+$/.test(e)}function Q(e){return e[0].toUpperCase()+e.slice(1).toLowerCase()}function J(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const{xlsx:n,thisRow:l}=t;let r=n?L(e):T(e);e.table&&(r+=e.table);const o=e.columns?.length??0,s=e.sections?.length??0;if(1!==s||o)if(s||1!==o){r+="[";const t=!l&&1===s&&"this row"===e.sections[0].toLowerCase();t?r+="@":s&&(r+=e.sections.map((e=>`[#${Q(e)}]`)).join(","),o&&(r+=",")),t&&1===e.columns.length&&!V(e.columns[0])?r+=K(e.columns[0]):o&&(r+=e.columns.slice(0,2).map((e=>`[${K(e)}]`)).join(":")),r+="]"}else r+=`[${K(e.columns[0])}]`;else r+=`[#${Q(e.sections[0])}]`;return r}const ee=/^(?!!)(\[(?:[^\]])+\])?([0-9A-Za-z._¡¤§¨ª\u00ad¯-\uffff]+)?(?=!)/,te=/^'(?:''|[^'])*('|$)(?=!)/,ne="\\$?[A-Z]{1,3}\\$?[1-9][0-9]{0,6}",le="\\$?[A-Z]{1,3}",re="\\$?[1-9][0-9]{0,6}",oe="(?![a-z0-9_\\u00a1-\\uffff])",se=new RegExp(`^${le}:${le}${oe}`,"i"),ue=new RegExp(`^${re}:${re}${oe}`,"i"),ie=new RegExp(`^${ne}${oe}`,"i"),ce=new RegExp(`^((${le}|${re}):${ne}|${ne}:(${le}|${re}))(?![\\w($.])`,"i"),ae="(?:R(?:\\[[+-]?\\d+\\]|[1-9][0-9]{0,6})?)",fe="(?:C(?:\\[[+-]?\\d+\\]|[1-9][0-9]{0,4})?)",pe=new RegExp(`^${fe}(:${fe})?${oe}`,"i"),he=new RegExp(`^${ae}(:${ae})?${oe}`,"i"),ge=new RegExp(`^(?:(?=[RC])${ae}${fe})${oe}`,"i"),de=new RegExp(`^(${ae}${fe}(:${fe}|:${ae})(?![[\\d])|(${ae}|${fe})(:${ae}${fe}))${oe}`,"i"),xe=/^[a-zA-Z\\_\u00a1-\uffff][a-zA-Z0-9\\_.?\u00a1-\uffff]{0,254}/i;function ye(e,t){return n=>{const l=t.exec(n);if(l)return{type:e,value:l[0]}}}function me(e){const t=xe.exec(e);if(t){const e=t[0].toLowerCase();return"\\"===e[0]&&t[0].length<3||("r"===e||"c"===e)?null:{type:r,value:t[0]}}}const ve=/^'(?:[^[\]]+?)?(?:\[(.+?)\])?(?:[^[\]]+?)'$/,$e=/^'\[(.+?)\]'$/;function we(e,t){const n=te.exec(e);if(n){const e=n[0];if(t.xlsx&&$e.test(e)||ve.test(e))return{type:"context_quote",value:e}}const l=ee.exec(e);if(l){const[,e,n]=l;if(e&&n||n||e&&!n&&t.xlsx)return{type:"context",value:l[0]}}}function Ee(e){const t=Y(e);if(t){let n=t.length;for(;" "===e[n];)n++;if("!"!==e[n])return{type:o,value:t.token}}return null}const Re=/([RC])(\[?)(-?\d+)/gi,Ne=/(\d+|[a-zA-Z]+)/gi;function be(e,t){let r,o;if(t.r1c1){if(t.allowTernary&&(r=de.exec(e))?o={type:l,value:r[0]}:(r=ge.exec(e))?o={type:"range",value:r[0]}:((r=he.exec(e))||(r=pe.exec(e)))&&(o={type:n,value:r[0]}),o){for(Re.lastIndex=0;null!==(r=Re.exec(o.value));){const e=("R"===r[1]?1048575:16383)+(r[2]?0:1),t=parseInt(r[3],10);if(t>e||t<-e)return null}return o}}else if(t.allowTernary&&(r=ce.exec(e))?o={type:l,value:r[0]}:(r=se.exec(e))||(r=ue.exec(e))?o={type:n,value:r[0]}:(r=ie.exec(e))&&(o={type:"range",value:r[0]}),o){for(Ne.lastIndex=0;null!==(r=Ne.exec(o.value));)if(/^\d/.test(r[1])){if(parseInt(r[1],10)-1>1048575)return null}else if(U(r[1])>16383)return null;return o}}const Ae=[ye(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),ye(e,/^(<=|>=|<>|[-+/*^%&<>=]|[{},;]|[()]|@|:|!|#)/),ye("func",/^[A-Z_]+[A-Z\d_.]*(?=\()/i),ye("bool",/^(TRUE|FALSE)\b/i),ye("newline",/^\n+/),ye("whitespace",/^[ \f\r\t\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]+/),ye("string",/^"(?:""|[^"])*("|$)/),we,be,Ee,ye("number",/^(?:\d+(\.\d+)?(?:[eE][+-]?\d+)?|\d+)/),me],Ce=[function(t,n){return n.r1c1?"!"===t[0]?{type:e,value:t[0]}:null:"!"===t[0]||":"===t[0]?{type:e,value:t[0]}:null},we,be,Ee,me],Te={};function Le(e,t){if(e.length){const n=e[0];t[n]=t[n]||{},Le(e.slice(1),t[n])}else t.$=!0}[["range",":","range"],["range"],[n],[l],["context","!","range",":","range"],["context","!","range"],["context","!",n],["context","!",l],["context_quote","!","range",":","range"],["context_quote","!","range"],["context_quote","!",n],["context_quote","!",l],[r],["context","!",r],["context_quote","!",r],[o],[r,o],["context","!",r,o],["context_quote","!",r,o]].forEach((e=>Le(e.concat().reverse(),Te)));const Ie=function(t,n,l){let r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:0;const o=t[l-r];if(o){const s=o.type===e?o.value:o.type;if(s in n)return Ie(t,n[s],l,r+1)}return n.$?r:0};function ke(e){const t=[];for(let n=e.length-1;n>=0;n--){let l=e[n];const r=Ie(e,Te,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 Oe=(e,t)=>e&&e.type===t,_e={withLocation:!1,mergeRefs:!0,allowTernary:!1,negativeNumbers:!0,r1c1:!1},Ue=e=>e.type===r||"func"===e.type,Fe=t=>!Oe(t,e)||"%"===t.value||"}"===t.value||")"===t.value||"#"===t.value;function Se(t){let n,l=0,o=0;for(const u of t){if(u.type===e)if("("===u.value){if(o++,"func"===n.type){const e=n.value.toLowerCase();"lambda"!==e&&"let"!==e||(l=o)}}else")"===u.value&&(o--,o<l&&(l=0));else l&&u.type===s&&/^[rc]$/.test(u.value)&&(u.type=r);n=u}return t}function Me(t,n){let l=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};const r=Object.assign({},_e,l),{withLocation:o,mergeRefs:u,negativeNumbers:i}=r,c=[];let a=0,f=0,p=0,h=null,g=null,d=null;const x=e=>{const t=e.type===s,n=d&&d.type===s;d&&(t&&n||t&&Ue(d)||n&&Ue(e))?(d.value+=e.value,d.type=s,o&&(d.loc[1]=e.loc[1])):(c.push(e),d=e,"whitespace"!==e.type&&"newline"!==e.type&&(g=h,h=e))};if(/^=/.test(t)){a++,x({type:"fx_prefix",value:"=",...o?{loc:[0,1]}:{}})}for(;a<t.length;){const l=a,u=t.slice(a);let y="",m="";for(let e=0;e<n.length;e++){const t=n[e](u,r);if(t){y=t.type,m=t.value,a+=m.length;break}}y||(y=s,m=t[a],a++);const v={type:y,value:m,...o?{loc:[l,a]}:{}};if(d&&"func"===d.type&&"("===m){const e=d.value.toLowerCase();"lambda"!==e&&"let"!==e||f++}if(y===s){const e=m.toLowerCase();p+="r"===e||"c"===e?1:0}if("string"===y){const e=m.length;if('""'===m);else if('"'===m||'"'!==m[e-1])v.unterminated=!0;else if('""'!==m&&'"'===m[e-2]){let t=e-1;for(;'"'===m[t];)t--;!(t+1)^(e-t+1)%2==0&&(v.unterminated=!0)}}if(i&&"number"===y){const t=d;if(t&&Oe(t,e)&&"-"===t.value&&(!g||Oe(g,"fx_prefix")||!Fe(g))){const e=c.pop();v.value="-"+m,o&&(v.loc[0]=e.loc[0]),h=g,d=c[c.length-1]}}x(v)}return p&&f&&Se(c),u?ke(c):c}function De(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return Me(e,Ae,t)}function ze(e){return!!e&&("range"===e.type||e.type===n||e.type===l)}function je(e){return!!e&&("range"===e.type||e.type===n||e.type===l||e.type===o||e.type===r)}function Be(e){return!!e&&("bool"===e.type||e.type===t||"number"===e.type||"string"===e.type)}function Ze(e){return!!e&&e.type===t}function qe(e){return!!e&&("whitespace"===e.type||"newline"===e.type)}function Pe(e){return!!e&&"func"===e.type}function Xe(e){return!!e&&"fx_prefix"===e.type}function We(t){return!!t&&t.type===e}const He="(END)",Ye=["ANCHORARRAY","CHOOSE","DROP","IF","IFS","INDEX","INDIRECT","LAMBDA","LET","OFFSET","REDUCE","SINGLE","SWITCH","TAKE","XLOOKUP"],Ge=e=>Ye.includes(e.toUpperCase()),Ke=function(e){let t=arguments.length>1&&void 0!==arguments[1]&&arguments[1];const n=(e&&e.value)+"";return!!je(e)||(!(!t||!We(e)||":"!==n&&","!==n&&n.trim())||(!(!Pe(e)||!Ge(n))||!(!Ze(e)||"#REF!"!==n)))},Ve=e=>!!e&&(e.type===c||("ErrorLiteral"===e.type||e.type===t)&&"#REF!"===e.value||e.type===i&&(":"===e.operator||" "===e.operator||","===e.operator)||je(e)||e.type===a&&Ge(e.callee.name)),Qe={};let Je,et,tt,nt=!1,lt=!1;function rt(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;const n=new Error(e);throw n.source=et.map((e=>e.value)).join(""),n.sourceOffset=et.slice(0,t??tt).reduce(((e,t)=>e+t.value.length),0),n}function ot(){let e,t=arguments.length>0&&void 0!==arguments[0]&&arguments[0],n=tt;do{e=et[++n]}while(e&&(qe(e)||We(e)&&"("===e.value));return Ke(e,t)}function st(){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&&rt(`Expected ${e} but got ${Je.id}`),qe(et[tt])){const e=Ve(t),n=e&&ot(!1),l=e&&"("===et[tt+1].value;if(!n&&!l)for(;qe(et[tt]);)tt++}if(tt>=et.length)return void(Je=Qe[He]);const n=et[tt];let l;return tt+=1,n.unterminated&&rt("Encountered an unterminated token"),We(n)?(l=Qe[n.value],l||rt(`Unknown operator ${n.value}`)):qe(n)?l=Qe["(WHITESPACE)"]:Be(n)?l=Qe.Literal:je(n)?l=Qe[c]:Pe(n)?l=Qe["(FUNCTION)"]:rt(`Unexpected ${n.type} token: ${n.value}`),Je=Object.create(l),Je.type=n.type,Je.value=n.value,n.loc&&(Je.loc=[...n.loc]),Je}function ut(e){let t=Je;st(null,t);let n=t.nud();for(;e<Je.lbp;)t=Je,st(null,t),n=t.led(n);return n}const it={nud:()=>rt("Invalid syntax"),led:()=>rt("Missing operator")};function ct(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=Qe[e];return n?t>=n.lbp&&(n.lbp=t):(n={...it},n.id=e,n.value=e,n.lbp=t,Qe[e]=n),n}function at(e,t,n){const l=ct(e,t);return l.led=n||function(e){this.type=i,this.operator=this.value,delete this.value;const n=ut(t);return this.arguments=[e,n],this.loc&&(this.loc=[e.loc[0],n.loc[1]]),this},l}function ft(e,t){const n=ct(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 pt(e,t){const n=ct(e);return n.nud=t||function(){this.type=u,this.operator=this.value,delete this.value;const e=ut(70);return this.arguments=[e],this.loc&&(this.loc[1]=e.loc[1]),this},n}function ht(e,t){return at(e,t,(function(n){Ve(n)||rt(`Unexpected ${e} operator`);const l=ut(t);return Ve(l)||rt(`Unexpected ${Je.type} following ${this.id}`),this.type=i,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}))}ct(He),ht(":",80);const gt=ht(",",80);ht("(WHITESPACE)",80);const dt=e=>{const t=gt.lbp>0;return null!=e&&(gt.lbp=e?80:0),t};function xt(e){const t=[],n={};let l,r=!1;const o=dt(!1);if(")"!==Je.id)for(;!r;){qe(Je)&&st();const e=tt,o=ut(0);if(","===Je.id){if(o.type===c&&"name"===o.kind){const e=o.value.toLowerCase();e in n&&rt("Duplicate name: "+o.value),n[e]=1;const l={type:"Identifier",name:o.value};o.loc&&(l.loc=o.loc),t.push(l)}else tt=e,rt("LAMBDA argument is not a name");st(",")}else l=o,r=!0}return dt(o),delete this.value,this.type="LambdaExpression",this.params=t,this.body=l||null,e.loc&&(this.loc=[e.loc[0],Je.loc[1]]),st(")",this),this}function yt(e){const t=[],n=[],l={};let r,o=0;const s=(e,s)=>{if(r&&rt("Unexpected argument following calculation"),s&&o>=2)r=e;else{if(!(o%2))if(e&&e.type===c&&"name"===e.kind){const n=e.value.toLowerCase();n in l&&rt("Duplicate name: "+e.value),l[n]=1,t.push({type:"Identifier",name:e.value,loc:e.loc})}else o>=2?r=e:rt("Argument is not a name");else n.push(e)}o++},u=dt(!1);let i=!1;if(")"!==Je.id){for(;")"!==Je.id;)if(qe(Je)&&st(),","===Je.id)s(null),i=!0,st();else{s(ut(0),","!==Je.id),i=!1,","===Je.id&&(st(","),i=!0)}dt(u)}i&&s(null,!0),void 0===r&&rt("Unexpected end of arguments"),dt(u),delete this.value,this.type=f,this.declarations=[],t.length||rt("Unexpected end of arguments");for(let e=0;e<t.length;e++){const l={type:"LetDeclarator",id:t[e],init:n[e],loc:t[e].loc&&[t[e].loc[0],n[e].loc[1]]};this.declarations.push(l)}return this.body=r,e.loc&&(this.loc=[e.loc[0],Je.loc[1]]),st(")",this),this}function mt(){let e=1;return()=>"fxg"+e++}function vt(e,t){return null==e&&null==t||e===t}function $t(e,t){if(Array.isArray(e)!==Array.isArray(t)||e.length!==t.length)return!1;for(let n=0;n<e.length;n++)if(!vt(e[n],t[n]))return!1;return!0}function wt(e,t){return!e&&!t||String(e).toLowerCase()===String(t).toLowerCase()}function Et(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(!$t(e.columns,t.columns))return!1;if(!$t(e.sections,t.sections))return!1}return!!(!e.range&&!t.range||vt(e.range.top,t.range.top)&&vt(e.range.bottom,t.range.bottom)&&vt(e.range.left,t.range.left)&&vt(e.range.right,t.range.right))&&!(!wt(e.workbookName,t.workbookName)||!wt(e.sheetName,t.sheetName))}function Rt(e,t,n){return e.sheetName||(e.sheetName=t),e.workbookName||(e.workbookName=n),e}ft("%"),ft("#",(function(e){return Ve(e)||rt("# expects a reference"),this.type=u,this.operator=this.value,delete this.value,this.arguments=[e],this})),pt("+"),pt("-"),pt("@"),at("^",50),at("*",40),at("/",40),at("+",30),at("-",30),at("&",20),at("=",10),at("<",10),at(">",10),at("<=",10),at(">=",10),at("<>",10),ct("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},ct(c).nud=function(){return this.type===r?this.kind="name":this.type===o?this.kind="table":this.type===n?this.kind="beam":this.kind="range",this.type=c,this},ct(")"),pt("(",(function(){const e=dt(!0),t=ut(0);return st(")",t),dt(e),t})),ct("(FUNCTION)").nud=function(){return this},at("(",90,(function(e){let t={type:"Identifier",name:e.value};"(FUNCTION)"!==e.id&&("LambdaExpression"===e.type||e.type===a||e.type===f||e.type===c||e.type===u&&"#"===e.value||"ErrorLiteral"===e.type&&"#REF!"===e.value?t=e:rt("Unexpected call",tt-1));const n=e.value.toLowerCase();if("lambda"===n)return xt.call(this,e);if("let"===n)return yt.call(this,e);const l=[];let r=!1;if(")"!==Je.id){const e=dt(!1);for(;")"!==Je.id;)if(qe(Je)&&st(),","===Je.id)l.push(null),r=!0,st();else{const e=ut(0);l.push(e),r=!1,","===Je.id&&(st(","),r=!0)}dt(e)}r&&l.push(null);const o=Je;return delete this.value,this.type=a,this.callee=t,e.loc&&(this.callee.loc=[...e.loc]),this.arguments=l,e.loc&&(this.loc=[e.loc[0],o.loc[1]]),st(")",this),this})),ct("}"),ct(";"),pt("{",(function(){"}"===Je.id&&rt("Unexpected empty array");let e=[],t=!1;const n=[e],l=dt(!1);for(;!t;){if(qe(Je)&&st(),Be(Je))e.push(Qe.Literal.nud.call(Je)),st();else if(nt&&Ve(Je))e.push(Qe[c].nud.call(Je)),st();else if(lt&&Pe(Je)){const t=ut(0);e.push(t)}else rt(`Unexpected ${Je.type} in array: ${Je.value}`);","===Je.id?st(","):";"===Je.id?(st(";"),e=[],n.push(e)):t=!0}const r=Je;return st("}"),dt(l),this.type="ArrayExpression",this.elements=n,this.loc&&(this.loc[1]=r.loc[1]),delete this.value,this}));const Nt=(e,t,n)=>Math.min(Math.max(t,e),n);function bt(e,t){return t?String(e+1):e?"["+e+"]":""}function At(e){let{r0:t,c0:n,r1:l,c1:r}=e;const{$c0:o,$c1:s,$r0:u,$r1:i}=e,c=null==t,a=null==n;let f=null==l,p=null==r;t=Nt(u?0:-1048575,0|t,1048575),n=Nt(o?0:-16383,0|n,16383),!c&&f&&!a&&p?(l=t,f=!1,r=n,p=!1):(l=Nt(i?0:-1048575,0|l,1048575),r=Nt(s?0:-16383,0|r,16383));if(0===t&&l>=1048575&&!a&&!p||c&&f){const e=bt(n,o),t=bt(r,s);return"C"+(e===t?e:e+":C"+t)}if(0===n&&r>=16383&&!c&&!f||a&&p){const e=bt(t,u),n=bt(l,i);return"R"+(e===n?e:e+":R"+n)}const h=bt(t,u),g=bt(l,i),d=bt(n,o),x=bt(r,s);return c||f||a||p?(c?"":"R"+h)+(a?"":"C"+d)+":"+(f?"":"R"+g)+(p?"":"C"+x):h!==g||d!==x?"R"+h+"C"+d+":R"+g+"C"+x:"R"+h+"C"+d}function Ct(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 s=/^C(?:\[([+-]?\d+)\]|(\d+))?/.exec(e);return s&&(s[1]?(n=parseInt(s[1],10),r=!1):s[2]?(n=parseInt(s[2],10)-1,r=!0):(n=0,r=!1),e=e.slice(s[0].length)),!o&&!s||e.length?null:[t,n,l,r]}function Tt(e){let t=null;const[n,l]=e.split(":",2),r=Ct(n);if(r){const[e,n,o,s]=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:s,$r1:!1,$c1:s}:{r0:e||0,c0:n||0,r1:e||0,c1:n||0,$r0:o||!1,$c0:s||!1,$r1:o||!1,$c1:s||!1};{const r=Ct(l);if(!r)return null;{t={};const[l,u,i,c]=r;null!=e&&null!=l?(t.r0=o===i?Math.min(e,l):e,t.$r0=o,t.r1=o===i?Math.max(e,l):l,t.$r1=i):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=i,t.r1=null,t.$r1=i):null==e&&null==l&&(t.r0=null,t.$r0=!1,t.r1=null,t.$r1=!1),null!=n&&null!=u?(t.c0=s===c?Math.min(n,u):n,t.$c0=s,t.c1=s===c?Math.max(n,u):u,t.$c1=c):null!=n&&null==u?(t.c0=n,t.$c0=s,t.c1=null,t.$c1=s):null==n&&null!=u?(t.c0=u,t.$c0=c,t.c1=null,t.$c1=c):null==n&&null==u&&(t.c0=null,t.$c0=!1,t.c1=null,t.$c1=!1)}}}return t}function Lt(e){let{allowNamed:t=!0,allowTernary:n=!1,xlsx:l=!1}=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const r=A(e,{allowNamed:t,allowTernary:n,xlsx:l,r1c1:!0});if(r&&(r.r0||r.name)){const e=r.r1?Tt(r.r0+":"+r.r1):Tt(r.r0);return r.name||e?(r.range=e,delete r.r0,delete r.r1,r):null}return null}function It(e){let{xlsx:t=!1}=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const n=t?L(e):T(e);return n+(e.name?e.name:At(e.range))}const kt=(e,t,n)=>null==t?null:e?t:t-n,Ot={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 Ut={wrapEdges:!0,mergeRefs:!0,allowTernary:!0,xlsx:!1};const Ft=Object.freeze({OPERATOR:e,BOOLEAN:"bool",ERROR:t,NUMBER:"number",FUNCTION:"func",NEWLINE:"newline",WHITESPACE:"whitespace",STRING:"string",CONTEXT:"context",CONTEXT_QUOTE:"context_quote",REF_RANGE:"range",REF_BEAM:n,REF_TERNARY:l,REF_NAMED:r,REF_STRUCT:o,FX_PREFIX:"fx_prefix",UNKNOWN:s}),St=Object.freeze({UNARY:u,BINARY:i,REFERENCE:c,LITERAL:"Literal",ERROR:"ErrorLiteral",CALL:a,ARRAY:"ArrayExpression",IDENTIFIER:"Identifier"});exports.MAX_COLS=16383,exports.MAX_ROWS=1048575,exports.addA1RangeBounds=B,exports.addTokenMeta=function(e){let{sheetName:t="",workbookName:r=""}=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const u=[];let i=null;const c=mt(),a=[],f=()=>u.length+(i?1:0);return e.forEach(((e,p)=>{if(e.index=p,e.depth=f(),"("===e.value)u.push(e),e.depth=f();else if(")"===e.value){const t=u.pop();if(t){const n=c();e.groupId=n,e.depth=t.depth,t.groupId=n}else e.error=!0}else if("{"===e.value)i?e.error=!0:(i=e,e.depth=f());else if("}"===e.value){if(i){const t=c();e.groupId=t,e.depth=i.depth,i.groupId=t}else e.error=!0;i=null}else if("range"===e.type||e.type===n||e.type===l||e.type===o){const n=e.type===o?G(e.value,{allowTernary:!0,xlsx:!0}):z(e.value,{allowTernary:!0,xlsx:!0});if(n&&(n.range||n.columns)){n.source=e.value,Rt(n,t,r);const l=a.find((e=>Et(e,n)));l?e.groupId=l.groupId:(n.groupId=c(),e.groupId=n.groupId,a.push(n))}}else e.type===s&&(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(De(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,xlsx:s,thisRow:u}=n;if(r)throw new Error("fixRanges does not have an R1C1 mode");let i=0;return t.map((e=>{const t={...e};e.loc&&(t.loc=[...e.loc]);let n=0;if(t.type===o){const e=J(G(t.value,{xlsx:s}),{xlsx:s,thisRow:u});n=e.length-t.value.length,t.value=e}else if(ze(t)){const e=z(t.value,{xlsx:s,allowTernary:!0}),r=e.range;l&&B(r);const o=j(e,{xlsx:s});n=o.length-t.value.length,t.value=o}return i||n?(t.loc&&(t.loc[0]+=i),i+=n,t.loc&&(t.loc[1]+=i)):i+=n,t}))},exports.fromCol=U,exports.isError=Ze,exports.isFunction=Pe,exports.isFxPrefix=Xe,exports.isLiteral=Be,exports.isOperator=We,exports.isRange=ze,exports.isReference=je,exports.isWhitespace=qe,exports.mergeRefTokens=ke,exports.nodeTypes=St,exports.parse=function(e,t){if("string"==typeof e)et=De(e,{withLocation:!1,...t,mergeRefs:!0});else{if(!Array.isArray(e))throw new Error("Parse requires a string or array of tokens.");et=e}for(nt=t?.permitArrayRanges,lt=t?.permitArrayCalls,tt=0;qe(et[tt])||Xe(et[tt]);)tt++;st(),dt(!0);const n=ut(0);return st(He),n},exports.parseA1Ref=z,exports.parseR1C1Ref=Lt,exports.parseStructRef=G,exports.stringifyA1Ref=j,exports.stringifyR1C1Ref=It,exports.stringifyStructRef=J,exports.toCol=F,exports.tokenTypes=Ft,exports.tokenize=De,exports.translateToA1=function(e,n){let l=arguments.length>2&&void 0!==arguments[2]?arguments[2]:Ut;const r=D(n),o="string"==typeof e,s={...Ut,...l},u=o?De(e,{withLocation:!1,mergeRefs:s.mergeRefs,xlsx:s.xlsx,allowTernary:s.allowTernary,r1c1:!0}):e;let i=0;const c={xlsx:s.xlsx,allowTernary:s.allowTernary};return u.forEach((e=>{if(ze(e)){const n=e.value,l=Lt(n,c),o=l.range,u={},a=_t(o.r0,o.$r0,r.top,1048575,s.wrapEdges),f=_t(o.r1,o.$r1,r.top,1048575,s.wrapEdges);a>f?(u.top=f,u.$top=o.$r1,u.bottom=a,u.$bottom=o.$r0):(u.top=a,u.$top=o.$r0,u.bottom=f,u.$bottom=o.$r1);const p=_t(o.c0,o.$c0,r.left,16383,s.wrapEdges),h=_t(o.c1,o.$c1,r.left,16383,s.wrapEdges);p>h?(u.left=h,u.$left=o.$c1,u.right=p,u.$right=o.$c0):(u.left=p,u.$left=o.$c0,u.right=h,u.$right=o.$c1),isNaN(a)||isNaN(f)||isNaN(p)||isNaN(h)?(e.type=t,e.value="#REF!",delete e.groupId):(l.range=u,e.value=j(l,c)),e.loc&&(e.loc[0]+=i,i+=e.value.length-n.length,e.loc[1]+=i)}else i&&e.loc&&(e.loc[0]+=i,e.loc[1]+=i)})),o?u.map((e=>e.value)).join(""):u},exports.translateToR1C1=function(e,t){let{xlsx:n=!1,allowTernary:l=!0}=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};const{top:r,left:o}=D(t),s="string"==typeof e,u=s?De(e,{...Ot,xlsx:n,allowTernary:l}):e;let i=0;const c={xlsx:n,allowTernary:l};return u.forEach((e=>{if(ze(e)){const t=e.value,n=z(t,c),l=n.range,s={};s.r0=kt(l.$top,l.top,r),s.r1=kt(l.$bottom,l.bottom,r),s.c0=kt(l.$left,l.left,o),s.c1=kt(l.$right,l.right,o),s.$r0=l.$top,s.$r1=l.$bottom,s.$c0=l.$left,s.$c1=l.$right,n.range=s,e.value=It(n,c),e.loc&&(e.loc[0]+=i,i+=e.value.length-t.length,e.loc[1]+=i)}else i&&e.loc&&(e.loc[0]+=i,e.loc[1]+=i)})),s?u.map((e=>e.value)).join(""):u};
|
|
1
|
+
"use strict";const e="operator",t="error",n="context",l="range_beam",r="range_ternary",o="range_named",s="structured",u="unknown",a="UnaryExpression",i="BinaryExpression",c="ReferenceIdentifier",f="CallExpression",p="LetExpression";function h(e){let t=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=!1,l="";const r=[],o=()=>{l&&r.push(t?l:{value:l,braced:n}),l=""};for(let t=0;t<e.length;t++){const r=e[t];"["===r?(o(),n=!0):"]"===r?(o(),n=!1):l+=r}return o(),r}function g(e){return{context:h(e,!0)}}function d(e){const t={},n=h(e);if(n.length>1)t.workbookName=n[n.length-2].value,t.sheetName=n[n.length-1].value;else if(1===n.length){const e=n[0];e.braced?t.workbookName=e.value:t.sheetName=e.value}return t}const m=e=>e&&(":"===e.value||".:"===e.value||":."===e.value||".:."===e.value)&&{operator:e.value},x=e=>e&&"range"===e.type&&{r0:e.value},y=e=>e&&e.type===r&&{r0:e.value},v=e=>e&&"range"===e.type&&{r1:e.value},$=t=>t&&t.type===e&&"!"===t.value&&{},w=e=>e&&e.type===l&&{r0:e.value},N=e=>e&&e.type===s&&{struct:e.value},E=(e,t)=>{const l=t.xlsx?d:g;return e&&e.type===n?l(e.value):e&&"context_quote"===e.type?l(e.value.slice(1,-1).replace(/''/g,"'")):void 0},R=e=>e&&e.type===o&&{name:e.value},b=[[y],[x,m,v],[x],[w],[E,$,y],[E,$,x,m,v],[E,$,x],[E,$,w]],A=b.concat([[R],[E,$,R],[N],[R,N],[E,$,R,N]]);function C(e,t){const n={withLocation:!1,mergeRefs:!1,allowTernary:!1,allowNamed:!0,r1c1:!1,xlsx:!1,...t},l=je(e,Le,n),r=n.xlsx?{workbookName:"",sheetName:"",r0:"",r1:"",name:"",operator:""}:{context:[],r0:"",r1:"",name:"",operator:""};l.length&&"fx_prefix"===l[0].type&&l.shift();const o=n.allowNamed?A:b;for(let e=0;e<o.length;e++){const t={...r};if(o[e].length===l.length){const r=o[e].every(((e,r)=>{const o=e(l[r],n);return Object.assign(t,o),o}));if(r)return t}}return null}const T=/[^0-9A-Za-z._¡¤§¨ª\u00ad¯-\uffff]/;function k(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+=+T.test(o),l++}}return n&&(t="'"+t.replace(/'/g,"''")+"'"),t?t+"!":t}function L(e){let t="",n=0;const{workbookName:l,sheetName:r}=e;return l&&(t+="["+l+"]",n+=+T.test(l)),r&&(t+=r,n+=+T.test(r)),n&&(t="'"+t.replace(/'/g,"''")+"'"),t?t+"!":t}const I=(e,t,n)=>Math.min(Math.max(t,e),n),_=(e,t)=>(t?"$":"")+S(e),O=(e,t)=>(t?"$":"")+String(e+1),U=String.fromCharCode;function F(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 S(e){return(e>=702?U(((e-702)/676-0)%26+65):"")+(e>=26?U((e/26-1)%26+65):"")+U(e%26+65)}function M(e){return"both"===e?".:.":"head"===e?".:":"tail"===e?":.":":"}function D(e,t){return e&&t?"both":e?"head":t?"tail":void 0}function z(e){let{top:t,left:n,bottom:l,right:r,trim:o}=e;const{$left:s,$right:u,$top:a,$bottom:i}=e,c=null==n,f=null==r,p=null==t,h=null==l;t=I(0,0|t,1048575),n=I(0,0|n,16383),!c&&!p&&f&&h?(l=t,r=n):(l=I(0,0|l,1048575),r=I(0,0|r,16383));const g=M(o);if(0===t&&l>=1048575&&!c&&!f&&(!(s&&!c||u&&!f)||n===r)||p&&h)return _(n,s)+g+_(r,u);return 0===n&&r>=16383&&!p&&!h&&(!(a&&!p||i&&!h)||t===l)||c&&f?O(t,a)+g+O(l,i):c||p||f||!h?c||!p||f||h?c||p||!f||h?!c||p||f||h?r!==n||l!==t||u!==s||i!==a?_(n,s)+O(t,a)+g+_(r,u)+O(l,i):_(n,s)+O(t,a):_(r,u)+O(t,a)+g+O(l,i):_(n,s)+O(t,a)+g+O(l,i):_(n,s)+O(l,i)+g+_(r,u):_(n,s)+O(t,a)+g+_(r,u)}function j(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]?F(t[2]):null,!!t[3],!!t[1]]:null;var n}function q(e){let t=null,n=null,l=null,r=null,o=!1,s=!1,u=!1,a=!1;const[i,c,f,p,h]=e.split(/(\.?:\.?)/);if(p||h)return null;const g=D(!!c&&"."===c.at(0),!!c&&"."===c.at(-1)),d=j(i),m=f?j(f):null;if(!d||f&&!m)return null;if(null!=d[0]&&null!=d[1]?[t,n,o,s]=d:null==d[0]&&null!=d[1]?[,n,,s]=d:null!=d[0]&&null==d[1]&&([t,,o]=d),f)null!=m[0]&&null!=m[1]?[l,r,u,a]=m:null==m[0]&&null!=m[1]?[,r,,a]=m:null!=m[0]&&null==m[1]&&([l,,u]=m);else{if(null==t||null==n)return null;l=t,r=n,u=o,a=s}null!=r&&(null==n||null!=n&&r<n)&&([n,r,s,a]=[r,n,a,s]),null!=l&&(null==t||null!=t&&l<t)&&([t,l,o,u]=[l,t,u,o]);const x={top:t,left:n,bottom:l,right:r,$top:o,$left:s,$bottom:u,$right:a};return g&&(x.trim=g),x}function B(e){let{allowNamed:t=!0,allowTernary:n=!1,xlsx:l=!1}=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const r=C(e,{allowNamed:t,allowTernary:n,xlsx:l,r1c1:!1});if(r&&(r.r0||r.name)){let e=null;return r.r0&&(e=q(r.r1?r.r0+r.operator+r.r1:r.r0)),e?l?{workbookName:r.workbookName,sheetName:r.sheetName,range:e}:{context:r.context,range:e}:r.name?l?{workbookName:r.workbookName,sheetName:r.sheetName,name:r.name}:{context:r.context,name:r.name}:null}return null}function Z(e){let{xlsx:t=!1}=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const n=t?L(e):k(e);return n+(e.name?e.name:z(e.range))}function P(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 X=/^\[('['#@[\]]|[^'#@[\]])+\]/i,W=/^([^#@[\]:]+)/i,G={headers:1,data:2,totals:4,all:8,"this row":16,"@":16},H=function(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return Object.freeze(t)},Y={0:H(),1:H("headers"),2:H("data"),4:H("totals"),8:H("all"),16:H("this row"),3:H("headers","data"),6:H("data","totals")},K=function(e){let t=!(arguments.length>1&&void 0!==arguments[1])||arguments[1],n=X.exec(e);if(n){const e=n[0].slice(1,-1).replace(/'(['#@[\]])/g,"$1");return[n[0],e]}return t&&(n=W.exec(e),n)?[n[0],n[0]]:null};function V(e){const t=[];let n,l,r=0,o=e,s=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,!G[e])return null;s|=G[e]}else if(l=K(o,!1))r+=l[0].length,t.push(l[1]);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(!G[e])return null;s|=G[e],o=o.slice(n[0].length),r+=n[0].length,l=!!n[2]}if(l&&(n=/^@/.exec(o))&&(s|=G["@"],o=o.slice(1),r+=1,l="]"!==o[0]),!(s in Y))return null;const u=l?K(e.slice(r)):null;if(u){if(r+=u[0].length,t.push(u[1]),o=e.slice(r),":"===o[0]){o=o.slice(1),r++;const e=K(o);if(!e)return null;r+=e[0].length,t.push(e[1])}l=!1}for(;" "===e[r];)r++;if(l||"]"!==e[r])return null;r++}const u=Y[s];return{columns:t,sections:u?u.concat():u,length:r,token:e.slice(0,r)}}function Q(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{xlsx:!1};const n=C(e,t);if(n&&n.struct){const e=V(n.struct);if(e&&e.length===n.struct.length)return t.xlsx?{workbookName:n.workbookName,sheetName:n.sheetName,table:n.name,columns:e.columns,sections:e.sections}:{context:n.context,table:n.name,columns:e.columns,sections:e.sections}}return null}function J(e){return e.replace(/([[\]#'@])/g,"'$1")}function ee(e){return!/^[a-zA-Z0-9\u00a1-\uffff]+$/.test(e)}function te(e){return e[0].toUpperCase()+e.slice(1).toLowerCase()}function ne(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const{xlsx:n,thisRow:l}=t;let r=n?L(e):k(e);e.table&&(r+=e.table);const o=e.columns?.length??0,s=e.sections?.length??0;if(1!==s||o)if(s||1!==o){r+="[";const t=!l&&1===s&&"this row"===e.sections[0].toLowerCase();t?r+="@":s&&(r+=e.sections.map((e=>`[#${te(e)}]`)).join(","),o&&(r+=",")),t&&1===e.columns.length&&!ee(e.columns[0])?r+=J(e.columns[0]):o&&(r+=e.columns.slice(0,2).map((e=>`[${J(e)}]`)).join(":")),r+="]"}else r+=`[${J(e.columns[0])}]`;else r+=`[#${te(e.sections[0])}]`;return r}const le=/^(?!!)(\[(?:[^\]])+\])?([0-9A-Za-z._¡¤§¨ª\u00ad¯-\uffff]+)?(?=!)/,re=/^'(?:''|[^'])*('|$)(?=!)/,oe="\\$?[A-Z]{1,3}\\$?[1-9][0-9]{0,6}",se="\\$?[A-Z]{1,3}",ue="\\$?[1-9][0-9]{0,6}",ae="(?![a-z0-9_\\u00a1-\\uffff])",ie=new RegExp(`^${se}\\.?:\\.?${se}${ae}`,"i"),ce=new RegExp(`^${ue}\\.?:\\.?${ue}${ae}`,"i"),fe=new RegExp(`^${oe}${ae}`,"i"),pe=new RegExp(`^((${se}|${ue})\\.?:\\.?${oe}|${oe}\\.?:\\.?(${se}|${ue}))(?![\\w($.])`,"i"),he="(?:R(?:\\[[+-]?\\d+\\]|[1-9][0-9]{0,6})?)",ge="(?:C(?:\\[[+-]?\\d+\\]|[1-9][0-9]{0,4})?)",de=new RegExp(`^${ge}(\\.?:\\.?${ge})?${ae}`,"i"),me=new RegExp(`^${he}(\\.?:\\.?${he})?${ae}`,"i"),xe=new RegExp(`^(?:(?=[RC])${he}${ge})${ae}`,"i"),ye=new RegExp(`^(${he}${ge}(\\.?:\\.?${ge}|\\.?:\\.?${he})(?![[\\d])|(${he}|${ge})(\\.?:\\.?${he}${ge}))${ae}`,"i"),ve=/^[a-zA-Z\\_\u00a1-\uffff][a-zA-Z0-9\\_.?\u00a1-\uffff]{0,254}/i;function $e(e,t){return n=>{const l=t.exec(n);if(l)return{type:e,value:l[0]}}}function we(e){const t=ve.exec(e);if(t){const e=t[0].toLowerCase();return"\\"===e[0]&&t[0].length<3||("r"===e||"c"===e)?null:{type:o,value:t[0]}}}const Ne=/^'(?:[^[\]]+?)?(?:\[(.+?)\])?(?:[^[\]]+?)'$/,Ee=/^'\[(.+?)\]'$/;function Re(e,t){const l=re.exec(e);if(l){const e=l[0];if(t.xlsx&&Ee.test(e)||Ne.test(e))return{type:"context_quote",value:e}}const r=le.exec(e);if(r){const[,e,l]=r;if(e&&l||l||e&&!l&&t.xlsx)return{type:n,value:r[0]}}}function be(e){const t=V(e);if(t){let n=t.length;for(;" "===e[n];)n++;if("!"!==e[n])return{type:s,value:t.token}}return null}const Ae=/([RC])(\[?)(-?\d+)/gi,Ce=/(\d+|[a-zA-Z]+)/gi;function Te(e,t){let n,o;if(t.r1c1){if(t.allowTernary&&(n=ye.exec(e))?o={type:r,value:n[0]}:(n=xe.exec(e))?o={type:"range",value:n[0]}:((n=me.exec(e))||(n=de.exec(e)))&&(o={type:l,value:n[0]}),o){for(Ae.lastIndex=0;null!==(n=Ae.exec(o.value));){const e=("R"===n[1]?1048575:16383)+(n[2]?0:1),t=parseInt(n[3],10);if(t>e||t<-e)return null}return o}}else if(t.allowTernary&&(n=pe.exec(e))?o={type:r,value:n[0]}:(n=ie.exec(e))||(n=ce.exec(e))?o={type:l,value:n[0]}:(n=fe.exec(e))&&(o={type:"range",value:n[0]}),o){for(Ce.lastIndex=0;null!==(n=Ce.exec(o.value));)if(/^\d/.test(n[1])){if(parseInt(n[1],10)-1>1048575)return null}else if(F(n[1])>16383)return null;return o}}const ke=[$e(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),$e("operator-trim",/^(\.:\.|\.:|:\.)/),$e(e,/^(<=|>=|<>|[-+/*^%&<>=]|[{},;]|[()]|@|:|!|#)/),$e("func",/^[A-Z_]+[A-Z\d_.]*(?=\()/i),$e("bool",/^(TRUE|FALSE)\b/i),$e("newline",/^\n+/),$e("whitespace",/^[ \f\r\t\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]+/),$e("string",/^"(?:""|[^"])*("|$)/),Re,Te,be,$e("number",/^(?:\d+(\.\d+)?(?:[eE][+-]?\d+)?|\d+)/),we],Le=[function(t,n){if(n.r1c1)return"!"===t[0]?{type:e,value:t[0]}:null;const l=/^(!|\.?:\.?)/.exec(t);return l?{type:e,value:l[1]}:null},Re,Te,be,we],Ie={};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",".:","range"],["range",":.","range"],["range",".:.","range"],["range"],[l],[r],[n,"!","range",":","range"],[n,"!","range",".:","range"],[n,"!","range",":.","range"],[n,"!","range",".:.","range"],[n,"!","range"],[n,"!",l],[n,"!",r],["context_quote","!","range",":","range"],["context_quote","!","range",".:","range"],["context_quote","!","range",":.","range"],["context_quote","!","range",".:.","range"],["context_quote","!","range"],["context_quote","!",l],["context_quote","!",r],[o],[n,"!",o],["context_quote","!",o],[s],[o,s],[n,"!",o,s],["context_quote","!",o,s]].forEach((e=>_e(e.concat().reverse(),Ie)));const Oe=function(t,n,l){let r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:0;const o=t[l-r];if(o){const s=o.type===e?o.value:o.type;if(s in n)return Oe(t,n[s],l,r+1)}return n.$?r:0};function Ue(e){const t=[];for(let n=e.length-1;n>=0;n--){let l=e[n];const r=Oe(e,Ie,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 Fe=(e,t)=>e&&e.type===t,Se={withLocation:!1,mergeRefs:!0,allowTernary:!1,negativeNumbers:!0,r1c1:!1},Me=e=>e.type===o||"func"===e.type,De=t=>!Fe(t,e)||"%"===t.value||"}"===t.value||")"===t.value||"#"===t.value;function ze(t){let n,l=0,r=0;for(const s of t){if(s.type===e)if("("===s.value){if(r++,"func"===n.type){const e=n.value.toLowerCase();"lambda"!==e&&"let"!==e||(l=r)}}else")"===s.value&&(r--,r<l&&(l=0));else l&&s.type===u&&/^[rc]$/.test(s.value)&&(s.type=o);n=s}return t}function je(t,n){let l=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};const r=Object.assign({},Se,l),{withLocation:o,mergeRefs:s,negativeNumbers:a}=r,i=[];let c=0,f=0,p=0;const h=[];let g=null,d=null,m=null;const x=e=>{const t=e.type===u,n=m&&m.type===u;m&&(t&&n||t&&Me(m)||n&&Me(e))?(m.value+=e.value,m.type=u,o&&(m.loc[1]=e.loc[1])):("operator-trim"===e.type&&(h.push(i.length),e.type=u),i.push(e),m=e,"whitespace"!==e.type&&"newline"!==e.type&&(d=g,g=e))};if("="===t.at(0)){c++,x({type:"fx_prefix",value:"=",...o?{loc:[0,1]}:{}})}for(;c<t.length;){const l=c,s=t.slice(c);let h="",y="";for(let e=0;e<n.length;e++){const t=n[e](s,r);if(t){h=t.type,y=t.value,c+=y.length;break}}h||(h=u,y=t[c],c++);const v={type:h,value:y,...o?{loc:[l,c]}:{}};if(m&&"func"===m.type&&"("===y){const e=m.value.toLowerCase();"lambda"!==e&&"let"!==e||f++}if(h===u){const e=y.toLowerCase();p+="r"===e||"c"===e?1:0}if("string"===h){const e=y.length;if('""'===y);else if('"'===y||'"'!==y[e-1])v.unterminated=!0;else if('""'!==y&&'"'===y[e-2]){let t=e-1;for(;'"'===y[t];)t--;!(t+1)^(e-t+1)%2==0&&(v.unterminated=!0)}}if(a&&"number"===h){const t=m;if(t&&Fe(t,e)&&"-"===t.value&&(!d||Fe(d,"fx_prefix")||!De(d))){const e=i.pop();v.value="-"+y,o&&(v.loc[0]=e.loc[0]),g=d,m=i[i.length-1]}}x(v)}p&&f&&ze(i);for(const t of h){const n=i[t-1],l=i[t-1];n&&"range"===n.type&&l&&"range"===l.type?i[t].type=e:i[t].type=u}return s?Ue(i):i}function qe(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return je(e,ke,t)}function Be(e){return!!e&&("range"===e.type||e.type===l||e.type===r)}function Ze(e){return!!e&&("range"===e.type||e.type===l||e.type===r||e.type===s||e.type===o)}function Pe(e){return!!e&&("bool"===e.type||e.type===t||"number"===e.type||"string"===e.type)}function Xe(e){return!!e&&e.type===t}function We(e){return!!e&&("whitespace"===e.type||"newline"===e.type)}function Ge(e){return!!e&&"func"===e.type}function He(e){return!!e&&"fx_prefix"===e.type}function Ye(t){return!!t&&t.type===e}const Ke="(END)",Ve=["ANCHORARRAY","CHOOSE","DROP","IF","IFS","INDEX","INDIRECT","LAMBDA","LET","OFFSET","REDUCE","SINGLE","SWITCH","TAKE","TRIMRANGE","XLOOKUP"],Qe=e=>Ve.includes(e.toUpperCase()),Je=function(e){let t=arguments.length>1&&void 0!==arguments[1]&&arguments[1];const n=(e&&e.value)+"";return!!Ze(e)||(!(!t||!Ye(e)||":"!==n&&","!==n&&n.trim())||(!(!Ge(e)||!Qe(n))||!(!Xe(e)||"#REF!"!==n)))},et=e=>!!e&&(e.type===c||("ErrorLiteral"===e.type||e.type===t)&&"#REF!"===e.value||e.type===i&&(":"===e.operator||" "===e.operator||","===e.operator)||Ze(e)||e.type===f&&Qe(e.callee.name)),tt={};let nt,lt,rt,ot=!1,st=!1;function ut(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;const n=new Error(e);throw n.source=lt.map((e=>e.value)).join(""),n.sourceOffset=lt.slice(0,t??rt).reduce(((e,t)=>e+t.value.length),0),n}function at(){let e,t=arguments.length>0&&void 0!==arguments[0]&&arguments[0],n=rt;do{e=lt[++n]}while(e&&(We(e)||Ye(e)&&"("===e.value));return Je(e,t)}function it(){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!==nt.id&&ut(`Expected ${e} but got ${nt.id}`),We(lt[rt])){const e=et(t),n=e&&at(!1),l=e&<[rt+1]&&"("===lt[rt+1].value;if(!n&&!l)for(;We(lt[rt]);)rt++}if(rt>=lt.length)return void(nt=tt[Ke]);const n=lt[rt];let l;return rt+=1,n.unterminated&&ut("Encountered an unterminated token"),Ye(n)?(l=tt[n.value],l||ut(`Unknown operator ${n.value}`)):We(n)?l=tt["(WHITESPACE)"]:Pe(n)?l=tt.Literal:Ze(n)?l=tt[c]:Ge(n)?l=tt["(FUNCTION)"]:ut(`Unexpected ${n.type} token: ${n.value}`),nt=Object.create(l),nt.type=n.type,nt.value=n.value,n.loc&&(nt.loc=[...n.loc]),nt}function ct(e){let t=nt;it(null,t);let n=t.nud();for(;e<nt.lbp;)t=nt,it(null,t),n=t.led(n);return n}const ft={nud:()=>ut("Invalid syntax"),led:()=>ut("Missing operator")};function pt(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=tt[e];return n?t>=n.lbp&&(n.lbp=t):(n={...ft},n.id=e,n.value=e,n.lbp=t,tt[e]=n),n}function ht(e,t,n){const l=pt(e,t);return l.led=n||function(e){this.type=i,this.operator=this.value,delete this.value;const n=ct(t);return this.arguments=[e,n],this.loc&&(this.loc=[e.loc[0],n.loc[1]]),this},l}function gt(e,t){const n=pt(e,0);return n.lbp=70,n.led=t||function(e){return this.type=a,this.operator=this.value,delete this.value,this.arguments=[e],this.loc&&(this.loc[0]=e.loc[0]),this},n}function dt(e,t){const n=pt(e);return n.nud=t||function(){this.type=a,this.operator=this.value,delete this.value;const e=ct(70);return this.arguments=[e],this.loc&&(this.loc[1]=e.loc[1]),this},n}function mt(e,t){return ht(e,t,(function(n){et(n)||ut(`Unexpected ${e} operator`);const l=ct(t);return et(l)||ut(`Unexpected ${nt.type} following ${this.id}`),this.type=i,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}))}pt(Ke),mt(":",80);const xt=mt(",",80);mt("(WHITESPACE)",80);const yt=e=>{const t=xt.lbp>0;return null!=e&&(xt.lbp=e?80:0),t};function vt(e){const t=[],n={};let l,r=!1;const o=yt(!1);if(")"!==nt.id)for(;!r;){We(nt)&&it();const e=rt,o=ct(0);if(","===nt.id){if(o.type===c&&"name"===o.kind){const e=o.value.toLowerCase();e in n&&ut("Duplicate name: "+o.value),n[e]=1;const l={type:"Identifier",name:o.value};o.loc&&(l.loc=o.loc),t.push(l)}else rt=e,ut("LAMBDA argument is not a name");it(",")}else l=o,r=!0}return yt(o),delete this.value,this.type="LambdaExpression",this.params=t,this.body=l||null,e.loc&&(this.loc=[e.loc[0],nt.loc[1]]),it(")",this),this}function $t(e){const t=[],n=[],l={};let r,o=0;const s=(e,s)=>{if(r&&ut("Unexpected argument following calculation"),s&&o>=2)r=e;else{if(!(o%2))if(e&&e.type===c&&"name"===e.kind){const n=e.value.toLowerCase();n in l&&ut("Duplicate name: "+e.value),l[n]=1,t.push({type:"Identifier",name:e.value,loc:e.loc})}else o>=2?r=e:ut("Argument is not a name");else n.push(e)}o++},u=yt(!1);let a=!1;if(")"!==nt.id){for(;")"!==nt.id;)if(We(nt)&&it(),","===nt.id)s(null),a=!0,it();else{s(ct(0),","!==nt.id),a=!1,","===nt.id&&(it(","),a=!0)}yt(u)}a&&s(null,!0),void 0===r&&ut("Unexpected end of arguments"),yt(u),delete this.value,this.type=p,this.declarations=[],t.length||ut("Unexpected end of arguments");for(let e=0;e<t.length;e++){const l={type:"LetDeclarator",id:t[e],init:n[e],loc:t[e].loc&&[t[e].loc[0],n[e].loc[1]]};this.declarations.push(l)}return this.body=r,e.loc&&(this.loc=[e.loc[0],nt.loc[1]]),it(")",this),this}function wt(){let e=1;return()=>"fxg"+e++}function Nt(e,t){return null==e&&null==t||e===t}function Et(e,t){if(Array.isArray(e)!==Array.isArray(t)||e.length!==t.length)return!1;for(let n=0;n<e.length;n++)if(!Nt(e[n],t[n]))return!1;return!0}function Rt(e,t){return!e&&!t||String(e).toLowerCase()===String(t).toLowerCase()}function bt(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(!Et(e.columns,t.columns))return!1;if(!Et(e.sections,t.sections))return!1}return!!(!e.range&&!t.range||Nt(e.range.top,t.range.top)&&Nt(e.range.bottom,t.range.bottom)&&Nt(e.range.left,t.range.left)&&Nt(e.range.right,t.range.right))&&!(!Rt(e.workbookName,t.workbookName)||!Rt(e.sheetName,t.sheetName))}function At(e,t,n){return e.sheetName||(e.sheetName=t),e.workbookName||(e.workbookName=n),e}gt("%"),gt("#",(function(e){return et(e)||ut("# expects a reference"),this.type=a,this.operator=this.value,delete this.value,this.arguments=[e],this})),dt("+"),dt("-"),dt("@"),ht("^",50),ht("*",40),ht("/",40),ht("+",30),ht("-",30),ht("&",20),ht("=",10),ht("<",10),ht(">",10),ht("<=",10),ht(">=",10),ht("<>",10),pt("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},pt(c).nud=function(){return this.type===o?this.kind="name":this.type===s?this.kind="table":this.type===l?this.kind="beam":this.kind="range",this.type=c,this},pt(")"),dt("(",(function(){const e=yt(!0),t=ct(0);return it(")",t),yt(e),t})),pt("(FUNCTION)").nud=function(){return this},ht("(",90,(function(e){let t={type:"Identifier",name:e.value};"(FUNCTION)"!==e.id&&("LambdaExpression"===e.type||e.type===f||e.type===p||e.type===c||e.type===a&&"#"===e.value||"ErrorLiteral"===e.type&&"#REF!"===e.value?t=e:ut("Unexpected call",rt-1));const n=e.value.toLowerCase();if("lambda"===n)return vt.call(this,e);if("let"===n)return $t.call(this,e);const l=[];let r=!1;if(")"!==nt.id){const e=yt(!1);for(;")"!==nt.id;)if(We(nt)&&it(),","===nt.id)l.push(null),r=!0,it();else{const e=ct(0);l.push(e),r=!1,","===nt.id&&(it(","),r=!0)}yt(e)}r&&l.push(null);const o=nt;return delete this.value,this.type=f,this.callee=t,e.loc&&(this.callee.loc=[...e.loc]),this.arguments=l,e.loc&&(this.loc=[e.loc[0],o.loc[1]]),it(")",this),this})),pt("}"),pt(";"),dt("{",(function(){"}"===nt.id&&ut("Unexpected empty array");let e=[],t=!1;const n=[e],l=yt(!1);for(;!t;){if(We(nt)&&it(),Pe(nt))e.push(tt.Literal.nud.call(nt)),it();else if(ot&&et(nt))e.push(tt[c].nud.call(nt)),it();else if(st&&Ge(nt)){const t=ct(0);e.push(t)}else ut(`Unexpected ${nt.type} in array: ${nt.value}`);","===nt.id?it(","):";"===nt.id?(it(";"),e=[],n.push(e)):t=!0}const r=nt;return it("}"),yt(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 Tt(e,t){return t?String(e+1):e?"["+e+"]":""}function kt(e){let{r0:t,c0:n,r1:l,c1:r}=e;const{$c0:o,$c1:s,$r0:u,$r1:a}=e,i=null==t,c=null==n;let f=null==l,p=null==r;const h=M(e.trim),g=!!e.trim;t=Ct(u?0:-1048575,0|t,1048575),n=Ct(o?0:-16383,0|n,16383),!i&&f&&!c&&p?(l=t,f=!1,r=n,p=!1):(l=Ct(a?0:-1048575,0|l,1048575),r=Ct(s?0:-16383,0|r,16383));if(0===t&&l>=1048575&&!c&&!p||i&&f){const e=Tt(n,o),t=Tt(r,s);return"C"+(e!==t||g?e+h+"C"+t:e)}if(0===n&&r>=16383&&!i&&!f||c&&p){const e=Tt(t,u),n=Tt(l,a);return"R"+(e!==n||g?e+h+"R"+n:e)}const d=Tt(t,u),m=Tt(l,a),x=Tt(n,o),y=Tt(r,s);return i||f||c||p?(i?"":"R"+d)+(c?"":"C"+x)+h+(f?"":"R"+m)+(p?"":"C"+y):d!==m||x!==y?"R"+d+"C"+x+h+"R"+m+"C"+y:"R"+d+"C"+x}function Lt(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 s=/^C(?:\[([+-]?\d+)\]|(\d+))?/.exec(e);return s&&(s[1]?(n=parseInt(s[1],10),r=!1):s[2]?(n=parseInt(s[2],10)-1,r=!0):(n=0,r=!1),e=e.slice(s[0].length)),!o&&!s||e.length?null:[t,n,l,r]}function It(e){let t=null;const[n,l,r,o]=e.split(/(\.?:\.?)/);if(o)return null;const s=Lt(n),u=D(!!l&&"."===l.at(0),!!l&&"."===l.at(-1));if(s){const[e,n,l,o]=s;if(r){const s=Lt(r);if(!s)return null;{t={};const[r,u,a,i]=s;null!=e&&null!=r?(t.r0=l===a?Math.min(e,r):e,t.$r0=l,t.r1=l===a?Math.max(e,r):r,t.$r1=a):null!=e&&null==r?(t.r0=e,t.$r0=l,t.r1=null,t.$r1=l):null==e&&null!=r?(t.r0=r,t.$r0=a,t.r1=null,t.$r1=a):null==e&&null==r&&(t.r0=null,t.$r0=!1,t.r1=null,t.$r1=!1),null!=n&&null!=u?(t.c0=o===i?Math.min(n,u):n,t.$c0=o,t.c1=o===i?Math.max(n,u):u,t.$c1=i):null!=n&&null==u?(t.c0=n,t.$c0=o,t.c1=null,t.$c1=o):null==n&&null!=u?(t.c0=u,t.$c0=i,t.c1=null,t.$c1=i):null==n&&null==u&&(t.c0=null,t.$c0=!1,t.c1=null,t.$c1=!1)}}else t=null!=e&&null==n?{r0:e,c0:null,r1:e,c1:null,$r0:l,$c0:!1,$r1:l,$c1:!1}:null==e&&null!=n?{r0:null,c0:n,r1:null,c1:n,$r0:!1,$c0:o,$r1:!1,$c1:o}:{r0:e||0,c0:n||0,r1:e||0,c1:n||0,$r0:l||!1,$c0:o||!1,$r1:l||!1,$c1:o||!1}}return t&&u&&(t.trim=u),t}function _t(e){let{allowNamed:t=!0,allowTernary:n=!1,xlsx:l=!1}=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const r=C(e,{allowNamed:t,allowTernary:n,xlsx:l,r1c1:!0});if(r&&(r.r0||r.name)){const e=r.r1?It(r.r0+r.operator+r.r1):It(r.r0);return e?l?{workbookName:r.workbookName,sheetName:r.sheetName,range:e}:{context:r.context,range:e}:r.name?l?{workbookName:r.workbookName,sheetName:r.sheetName,name:r.name}:{context:r.context,name:r.name}:null}return null}function Ot(e){let{xlsx:t=!1}=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const n=t?L(e):k(e);return n+(e.name?e.name:kt(e.range))}const Ut=(e,t,n)=>null==t?null:e?t:t-n,Ft={withLocation:!1,mergeRefs:!1,allowTernary:!0,r1c1:!1};function St(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 Mt={wrapEdges:!0,mergeRefs:!0,allowTernary:!0,xlsx:!1};const Dt=Object.freeze({OPERATOR:e,BOOLEAN:"bool",ERROR:t,NUMBER:"number",FUNCTION:"func",NEWLINE:"newline",WHITESPACE:"whitespace",STRING:"string",CONTEXT:n,CONTEXT_QUOTE:"context_quote",REF_RANGE:"range",REF_BEAM:l,REF_TERNARY:r,REF_NAMED:o,REF_STRUCT:s,FX_PREFIX:"fx_prefix",UNKNOWN:u}),zt=Object.freeze({UNARY:a,BINARY:i,REFERENCE:c,LITERAL:"Literal",ERROR:"ErrorLiteral",CALL:f,ARRAY:"ArrayExpression",IDENTIFIER:"Identifier"});exports.MAX_COLS=16383,exports.MAX_ROWS=1048575,exports.addA1RangeBounds=P,exports.addTokenMeta=function(e){let{sheetName:t="",workbookName:n=""}=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const o=[];let a=null;const i=wt(),c=[],f=()=>o.length+(a?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=i();e.groupId=n,e.depth=t.depth,t.groupId=n}else e.error=!0}else if("{"===e.value)a?e.error=!0:(a=e,e.depth=f());else if("}"===e.value){if(a){const t=i();e.groupId=t,e.depth=a.depth,a.groupId=t}else e.error=!0;a=null}else if("range"===e.type||e.type===l||e.type===r||e.type===s){const l=e.type===s?Q(e.value,{xlsx:!0}):B(e.value,{allowTernary:!0,xlsx:!0});if(l&&(l.range||l.columns)){l.source=e.value,At(l,t,n);const r=c.find((e=>bt(e,l)));r?e.groupId=r.groupId:(l.groupId=i(),e.groupId=l.groupId,c.push(l))}}else e.type===u&&(e.error=!0)})),e},exports.fixRanges=function e(t){let n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{addBounds:!1};if("string"==typeof t)return e(qe(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,xlsx:o,thisRow:u}=n;if(r)throw new Error("fixRanges does not have an R1C1 mode");let a=0;return t.map((e=>{const t={...e};e.loc&&(t.loc=[...e.loc]);let n=0;if(t.type===s){const e=ne(Q(t.value,{xlsx:o}),{xlsx:o,thisRow:u});n=e.length-t.value.length,t.value=e}else if(Be(t)){const e=B(t.value,{xlsx:o,allowTernary:!0}),r=e.range;l&&P(r);const s=Z(e,{xlsx:o});n=s.length-t.value.length,t.value=s}return a||n?(t.loc&&(t.loc[0]+=a),a+=n,t.loc&&(t.loc[1]+=a)):a+=n,t}))},exports.fromCol=F,exports.isError=Xe,exports.isFunction=Ge,exports.isFxPrefix=He,exports.isLiteral=Pe,exports.isOperator=Ye,exports.isRange=Be,exports.isReference=Ze,exports.isWhitespace=We,exports.mergeRefTokens=Ue,exports.nodeTypes=zt,exports.parse=function(e,t){if("string"==typeof e)lt=qe(e,{withLocation:!1,...t,mergeRefs:!0});else{if(!Array.isArray(e))throw new Error("Parse requires a string or array of tokens.");lt=e}for(ot=t?.permitArrayRanges,st=t?.permitArrayCalls,rt=0;We(lt[rt])||He(lt[rt]);)rt++;it(),yt(!0);const n=ct(0);return it(Ke),n},exports.parseA1Ref=B,exports.parseR1C1Ref=_t,exports.parseStructRef=Q,exports.stringifyA1Ref=Z,exports.stringifyR1C1Ref=Ot,exports.stringifyStructRef=ne,exports.toCol=S,exports.tokenTypes=Dt,exports.tokenize=qe,exports.translateToA1=function(e,n){let l=arguments.length>2&&void 0!==arguments[2]?arguments[2]:Mt;const r=q(n),o="string"==typeof e,s={...Mt,...l},u=o?qe(e,{withLocation:!1,mergeRefs:s.mergeRefs,xlsx:s.xlsx,allowTernary:s.allowTernary,r1c1:!0}):e;let a=0;const i={xlsx:s.xlsx,allowTernary:s.allowTernary};return u.forEach((e=>{if(Be(e)){const n=e.value,l=_t(n,i),o=l.range,u={},c=St(o.r0,o.$r0,r.top,1048575,s.wrapEdges),f=St(o.r1,o.$r1,r.top,1048575,s.wrapEdges);c>f?(u.top=f,u.$top=o.$r1,u.bottom=c,u.$bottom=o.$r0):(u.top=c,u.$top=o.$r0,u.bottom=f,u.$bottom=o.$r1);const p=St(o.c0,o.$c0,r.left,16383,s.wrapEdges),h=St(o.c1,o.$c1,r.left,16383,s.wrapEdges);p>h?(u.left=h,u.$left=o.$c1,u.right=p,u.$right=o.$c0):(u.left=p,u.$left=o.$c0,u.right=h,u.$right=o.$c1),o.trim&&(u.trim=o.trim),isNaN(c)||isNaN(f)||isNaN(p)||isNaN(h)?(e.type=t,e.value="#REF!",delete e.groupId):(l.range=u,e.value=Z(l,i)),e.loc&&(e.loc[0]+=a,a+=e.value.length-n.length,e.loc[1]+=a)}else a&&e.loc&&(e.loc[0]+=a,e.loc[1]+=a)})),o?u.map((e=>e.value)).join(""):u},exports.translateToR1C1=function(e,t){let{xlsx:n=!1,allowTernary:l=!0}=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};const{top:r,left:o}=q(t),s="string"==typeof e,u=s?qe(e,{...Ft,xlsx:n,allowTernary:l}):e;let a=0;const i={xlsx:n,allowTernary:l};return u.forEach((e=>{if(Be(e)){const t=e.value,n=B(t,i),l=n.range,s={};s.r0=Ut(l.$top,l.top,r),s.r1=Ut(l.$bottom,l.bottom,r),s.c0=Ut(l.$left,l.left,o),s.c1=Ut(l.$right,l.right,o),s.$r0=l.$top,s.$r1=l.$bottom,s.$c0=l.$left,s.$c1=l.$right,l.trim&&(s.trim=l.trim),n.range=s,e.value=Ot(n,i),e.loc&&(e.loc[0]+=a,a+=e.value.length-t.length,e.loc[1]+=a)}else a&&e.loc&&(e.loc[0]+=a,e.loc[1]+=a)})),s?u.map((e=>e.value)).join(""):u};
|
|
2
2
|
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnguanMiLCJzb3VyY2VzIjpbXSwic291cmNlc0NvbnRlbnQiOltdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIn0=
|
package/docs/API.md
CHANGED
|
@@ -915,16 +915,17 @@ A range in A1 style coordinates.
|
|
|
915
915
|
|
|
916
916
|
##### Properties
|
|
917
917
|
|
|
918
|
-
| Name | Type
|
|
919
|
-
| --------- |
|
|
920
|
-
| [$bottom] | `boolean` \| `null`
|
|
921
|
-
| [$left] | `boolean` \| `null`
|
|
922
|
-
| [$right] | `boolean` \| `null`
|
|
923
|
-
| [$top] | `boolean` \| `null`
|
|
924
|
-
| [bottom] | `number` \| `null`
|
|
925
|
-
| [left] | `number` \| `null`
|
|
926
|
-
| [right] | `number` \| `null`
|
|
927
|
-
| [top] | `number` \| `null`
|
|
918
|
+
| Name | Type | Description |
|
|
919
|
+
| --------- | -------------------------------- | ---------------------------------------------------------------------------------------------- |
|
|
920
|
+
| [$bottom] | `boolean` \| `null` | Signifies that bottom is a "locked" value |
|
|
921
|
+
| [$left] | `boolean` \| `null` | Signifies that left is a "locked" value |
|
|
922
|
+
| [$right] | `boolean` \| `null` | Signifies that right is a "locked" value |
|
|
923
|
+
| [$top] | `boolean` \| `null` | Signifies that top is a "locked" value |
|
|
924
|
+
| [bottom] | `number` \| `null` | Bottom row of the range |
|
|
925
|
+
| [left] | `number` \| `null` | Left column of the range |
|
|
926
|
+
| [right] | `number` \| `null` | Right column of the range |
|
|
927
|
+
| [top] | `number` \| `null` | Top row of the range |
|
|
928
|
+
| [trim] | `"head"` \| `"tail"` \| `"both"` | Should empty rows and columns at the top/left or bottom/right be discarded when range is read? |
|
|
928
929
|
|
|
929
930
|
---
|
|
930
931
|
|
package/lib/a1.js
CHANGED
|
@@ -71,13 +71,41 @@ export function toRow (top) {
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
export function toRelative (range) {
|
|
74
|
-
|
|
75
|
-
return { top, left, bottom, right, $left: false, $right: false, $top: false, $bottom: false };
|
|
74
|
+
return Object.assign({}, range, { $left: false, $right: false, $top: false, $bottom: false });
|
|
76
75
|
}
|
|
77
76
|
|
|
78
77
|
export function toAbsolute (range) {
|
|
79
|
-
|
|
80
|
-
|
|
78
|
+
return Object.assign({}, range, { $left: true, $right: true, $top: true, $bottom: true });
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* @ignore
|
|
83
|
+
* @param {'head' | 'tail' | 'both' | null | undefined} trim Does the range have trimming?
|
|
84
|
+
* @returns {string} The appropriate range join operator
|
|
85
|
+
*/
|
|
86
|
+
export function rangeOperator (trim) {
|
|
87
|
+
if (trim === 'both') {
|
|
88
|
+
return '.:.';
|
|
89
|
+
}
|
|
90
|
+
else if (trim === 'head') {
|
|
91
|
+
return '.:';
|
|
92
|
+
}
|
|
93
|
+
else if (trim === 'tail') {
|
|
94
|
+
return ':.';
|
|
95
|
+
}
|
|
96
|
+
return ':';
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function trimDirection (head, tail) {
|
|
100
|
+
if (head && tail) {
|
|
101
|
+
return 'both';
|
|
102
|
+
}
|
|
103
|
+
if (head) {
|
|
104
|
+
return 'head';
|
|
105
|
+
}
|
|
106
|
+
if (tail) {
|
|
107
|
+
return 'tail';
|
|
108
|
+
}
|
|
81
109
|
}
|
|
82
110
|
|
|
83
111
|
/**
|
|
@@ -90,7 +118,8 @@ export function toAbsolute (range) {
|
|
|
90
118
|
* @returns {string} An A1-style string represenation of a range
|
|
91
119
|
*/
|
|
92
120
|
export function toA1 (range) {
|
|
93
|
-
|
|
121
|
+
// eslint-disable-next-line prefer-const
|
|
122
|
+
let { top, left, bottom, right, trim } = range;
|
|
94
123
|
const { $left, $right, $top, $bottom } = range;
|
|
95
124
|
const noLeft = left == null;
|
|
96
125
|
const noRight = right == null;
|
|
@@ -107,37 +136,38 @@ export function toA1 (range) {
|
|
|
107
136
|
bottom = clamp(0, bottom | 0, MAX_ROWS);
|
|
108
137
|
right = clamp(0, right | 0, MAX_COLS);
|
|
109
138
|
}
|
|
139
|
+
const op = rangeOperator(trim);
|
|
110
140
|
// A:A
|
|
111
141
|
const allRows = top === 0 && bottom >= MAX_ROWS;
|
|
112
142
|
const haveAbsCol = ($left && !noLeft) || ($right && !noRight);
|
|
113
143
|
if ((allRows && !noLeft && !noRight && (!haveAbsCol || left === right)) || (noTop && noBottom)) {
|
|
114
|
-
return toColStr(left, $left) +
|
|
144
|
+
return toColStr(left, $left) + op + toColStr(right, $right);
|
|
115
145
|
}
|
|
116
146
|
// 1:1
|
|
117
147
|
const allCols = left === 0 && right >= MAX_COLS;
|
|
118
148
|
const haveAbsRow = ($top && !noTop) || ($bottom && !noBottom);
|
|
119
149
|
if ((allCols && !noTop && !noBottom && (!haveAbsRow || top === bottom)) || (noLeft && noRight)) {
|
|
120
|
-
return toRowStr(top, $top) +
|
|
150
|
+
return toRowStr(top, $top) + op + toRowStr(bottom, $bottom);
|
|
121
151
|
}
|
|
122
152
|
// A1:1
|
|
123
153
|
if (!noLeft && !noTop && !noRight && noBottom) {
|
|
124
|
-
return toColStr(left, $left) + toRowStr(top, $top) +
|
|
154
|
+
return toColStr(left, $left) + toRowStr(top, $top) + op + toColStr(right, $right);
|
|
125
155
|
}
|
|
126
156
|
// A:A1 => A1:1
|
|
127
157
|
if (!noLeft && noTop && !noRight && !noBottom) {
|
|
128
|
-
return toColStr(left, $left) + toRowStr(bottom, $bottom) +
|
|
158
|
+
return toColStr(left, $left) + toRowStr(bottom, $bottom) + op + toColStr(right, $right);
|
|
129
159
|
}
|
|
130
160
|
// A1:A
|
|
131
161
|
if (!noLeft && !noTop && noRight && !noBottom) {
|
|
132
|
-
return toColStr(left, $left) + toRowStr(top, $top) +
|
|
162
|
+
return toColStr(left, $left) + toRowStr(top, $top) + op + toRowStr(bottom, $bottom);
|
|
133
163
|
}
|
|
134
164
|
// A:A1 => A1:A
|
|
135
165
|
if (noLeft && !noTop && !noRight && !noBottom) {
|
|
136
|
-
return toColStr(right, $right) + toRowStr(top, $top) +
|
|
166
|
+
return toColStr(right, $right) + toRowStr(top, $top) + op + toRowStr(bottom, $bottom);
|
|
137
167
|
}
|
|
138
168
|
// A1:A1
|
|
139
169
|
if (right !== left || bottom !== top || $right !== $left || $bottom !== $top) {
|
|
140
|
-
return toColStr(left, $left) + toRowStr(top, $top) +
|
|
170
|
+
return toColStr(left, $left) + toRowStr(top, $top) + op +
|
|
141
171
|
toColStr(right, $right) + toRowStr(bottom, $bottom);
|
|
142
172
|
}
|
|
143
173
|
// A1
|
|
@@ -176,10 +206,11 @@ export function fromA1 (rangeString) {
|
|
|
176
206
|
let $left = false;
|
|
177
207
|
let $bottom = false;
|
|
178
208
|
let $right = false;
|
|
179
|
-
const [ part1, part2, part3 ] = rangeString.split(
|
|
180
|
-
if (part3) {
|
|
209
|
+
const [ part1, op1, part2, op2, part3 ] = rangeString.split(/(\.?:\.?)/);
|
|
210
|
+
if (op2 || part3) {
|
|
181
211
|
return null;
|
|
182
212
|
}
|
|
213
|
+
const trim = trimDirection(!!op1 && op1.at(0) === '.', !!op1 && op1.at(-1) === '.');
|
|
183
214
|
const p1 = splitA1(part1);
|
|
184
215
|
const p2 = part2 ? splitA1(part2) : null;
|
|
185
216
|
if (!p1 || (part2 && !p2)) {
|
|
@@ -225,7 +256,9 @@ export function fromA1 (rangeString) {
|
|
|
225
256
|
if (bottom != null && (top == null || (top != null && bottom < top))) {
|
|
226
257
|
[ top, bottom, $top, $bottom ] = [ bottom, top, $bottom, $top ];
|
|
227
258
|
}
|
|
228
|
-
|
|
259
|
+
const r = { top, left, bottom, right, $top, $left, $bottom, $right };
|
|
260
|
+
if (trim) { r.trim = trim; }
|
|
261
|
+
return r;
|
|
229
262
|
}
|
|
230
263
|
|
|
231
264
|
/**
|
|
@@ -263,17 +296,19 @@ export function parseA1Ref (refString, { allowNamed = true, allowTernary = false
|
|
|
263
296
|
if (d && (d.r0 || d.name)) {
|
|
264
297
|
let range = null;
|
|
265
298
|
if (d.r0) {
|
|
266
|
-
range = fromA1(d.r1 ? d.r0 +
|
|
299
|
+
range = fromA1(d.r1 ? d.r0 + d.operator + d.r1 : d.r0);
|
|
267
300
|
}
|
|
268
|
-
if (
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
return d;
|
|
301
|
+
if (range) {
|
|
302
|
+
return xlsx
|
|
303
|
+
? { workbookName: d.workbookName, sheetName: d.sheetName, range }
|
|
304
|
+
: { context: d.context, range };
|
|
273
305
|
}
|
|
274
|
-
|
|
275
|
-
return
|
|
306
|
+
if (d.name) {
|
|
307
|
+
return xlsx
|
|
308
|
+
? { workbookName: d.workbookName, sheetName: d.sheetName, name: d.name }
|
|
309
|
+
: { context: d.context, name: d.name };
|
|
276
310
|
}
|
|
311
|
+
return null;
|
|
277
312
|
}
|
|
278
313
|
return null;
|
|
279
314
|
}
|
package/lib/a1.spec.js
CHANGED
|
@@ -16,19 +16,8 @@ import { MAX_COLS, MAX_ROWS } from './constants.js';
|
|
|
16
16
|
Test.prototype.isA1Equal = function isA1Equal (expr, expect, opts) {
|
|
17
17
|
if (expect) {
|
|
18
18
|
expect = opts?.xlsx
|
|
19
|
-
? {
|
|
20
|
-
|
|
21
|
-
sheetName: '',
|
|
22
|
-
name: '',
|
|
23
|
-
range: null,
|
|
24
|
-
...expect
|
|
25
|
-
}
|
|
26
|
-
: {
|
|
27
|
-
context: [],
|
|
28
|
-
name: '',
|
|
29
|
-
range: null,
|
|
30
|
-
...expect
|
|
31
|
-
};
|
|
19
|
+
? { workbookName: '', sheetName: '', ...expect }
|
|
20
|
+
: { context: [], ...expect };
|
|
32
21
|
Object.assign(expect, expect);
|
|
33
22
|
if (expect.range && typeof expect.range === 'object') {
|
|
34
23
|
// mix in some defaults so we don't have to write things out in full
|
|
@@ -296,6 +285,56 @@ test('A1 partial ranges', t => {
|
|
|
296
285
|
t.end();
|
|
297
286
|
});
|
|
298
287
|
|
|
288
|
+
test('A1 trimmed ranges', t => {
|
|
289
|
+
const locks = { $top: true, $left: true, $bottom: true, $right: true };
|
|
290
|
+
const opts = [ {}, { xlsx: true } ];
|
|
291
|
+
for (const opt of opts) {
|
|
292
|
+
t.isA1Equal('A1:B2', { range: { top: 0, left: 0, bottom: 1, right: 1 } }, opt);
|
|
293
|
+
t.isA1Equal('A1.:B2', { range: { top: 0, left: 0, bottom: 1, right: 1, trim: 'head' } }, opt);
|
|
294
|
+
t.isA1Equal('A1:.B2', { range: { top: 0, left: 0, bottom: 1, right: 1, trim: 'tail' } }, opt);
|
|
295
|
+
t.isA1Equal('A1.:.B2', { range: { top: 0, left: 0, bottom: 1, right: 1, trim: 'both' } }, opt);
|
|
296
|
+
|
|
297
|
+
t.isA1Equal('$A$1:$B$2', { range: { top: 0, left: 0, bottom: 1, right: 1, ...locks } }, opt);
|
|
298
|
+
t.isA1Equal('$A$1.:$B$2', { range: { top: 0, left: 0, bottom: 1, right: 1, trim: 'head', ...locks } }, opt);
|
|
299
|
+
t.isA1Equal('$A$1:.$B$2', { range: { top: 0, left: 0, bottom: 1, right: 1, trim: 'tail', ...locks } }, opt);
|
|
300
|
+
t.isA1Equal('$A$1.:.$B$2', { range: { top: 0, left: 0, bottom: 1, right: 1, trim: 'both', ...locks } }, opt);
|
|
301
|
+
|
|
302
|
+
t.isA1Equal('J:J', { range: { top: null, left: 9, bottom: null, right: 9 } }, opt);
|
|
303
|
+
t.isA1Equal('J.:J', { range: { top: null, left: 9, bottom: null, right: 9, trim: 'head' } }, opt);
|
|
304
|
+
t.isA1Equal('J:.J', { range: { top: null, left: 9, bottom: null, right: 9, trim: 'tail' } }, opt);
|
|
305
|
+
t.isA1Equal('J.:.J', { range: { top: null, left: 9, bottom: null, right: 9, trim: 'both' } }, opt);
|
|
306
|
+
|
|
307
|
+
t.isA1Equal('10:10', { range: { top: 9, left: null, bottom: 9, right: null } }, opt);
|
|
308
|
+
t.isA1Equal('10.:10', { range: { top: 9, left: null, bottom: 9, right: null, trim: 'head' } }, opt);
|
|
309
|
+
t.isA1Equal('10:.10', { range: { top: 9, left: null, bottom: 9, right: null, trim: 'tail' } }, opt);
|
|
310
|
+
t.isA1Equal('10.:.10', { range: { top: 9, left: null, bottom: 9, right: null, trim: 'both' } }, opt);
|
|
311
|
+
|
|
312
|
+
t.isA1Equal('J10:J', null, { ...opt });
|
|
313
|
+
t.isA1Equal('J10:10', null, { ...opt });
|
|
314
|
+
t.isA1Equal('J10.:.J', null, { ...opt });
|
|
315
|
+
t.isA1Equal('J10.:.10', null, { ...opt });
|
|
316
|
+
t.isA1Equal('J10:J', { range: { top: 9, left: 9, bottom: null, right: 9 } }, { allowTernary: true, ...opt });
|
|
317
|
+
t.isA1Equal('J10:10', { range: { top: 9, left: 9, bottom: 9, right: null } }, { allowTernary: true, ...opt });
|
|
318
|
+
t.isA1Equal('J10.:.J', { range: { top: 9, left: 9, bottom: null, right: 9, trim: 'both' } }, { allowTernary: true, ...opt });
|
|
319
|
+
t.isA1Equal('J10.:.10', { range: { top: 9, left: 9, bottom: 9, right: null, trim: 'both' } }, { allowTernary: true, ...opt });
|
|
320
|
+
}
|
|
321
|
+
t.end();
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
test('A1 trimmed ranges vs named ranges', t => {
|
|
325
|
+
// named ranges cannot be trimmed
|
|
326
|
+
t.isA1Equal('name1.:.name1', null);
|
|
327
|
+
t.isA1Equal('name1.:.foo', null);
|
|
328
|
+
t.isA1Equal('foo.:.name1', null);
|
|
329
|
+
// prior to the intruduction of trimed ranges, the following would have
|
|
330
|
+
// been an expression: NAME:`foo.` OP:`:`, COLUMN:`bar`
|
|
331
|
+
t.isA1Equal('foo.:bar', { range: { left: 1395, right: 4460, trim: 'head' } });
|
|
332
|
+
// prior to the intruduction of trimed ranges, the following would have
|
|
333
|
+
// been an expression: NAME:`foo.` OP:`:`, CELL:`B2`
|
|
334
|
+
t.isA1Equal('foo.:B2', { range: { top: 1, left: 1, right: 4460, trim: 'head' } }, { allowTernary: true });
|
|
335
|
+
t.end();
|
|
336
|
+
});
|
|
337
|
+
|
|
299
338
|
test('A1 serialization', t => {
|
|
300
339
|
// cell: A1
|
|
301
340
|
t.is(toA1({ top: 9, bottom: 9, left: 2, right: 2 }), 'C10', 'C10');
|
|
@@ -343,6 +382,15 @@ test('A1 serialization', t => {
|
|
|
343
382
|
t.is(toA1({ top: 15e5, bottom: 15e5, left: 20000, right: 20000 }), 'XFD1048576', 'XFD1048576');
|
|
344
383
|
t.is(toA1({ top: 2, bottom: 2, left: 2.5, right: 2.5 }), 'C3', 'C3');
|
|
345
384
|
t.is(toA1({ top: 1.5, bottom: 2.5, left: 4.5, right: 8.5 }), 'E2:I3', 'E2:I3');
|
|
385
|
+
// triming
|
|
386
|
+
t.is(toA1({ top: 2, bottom: 2, left: 4, right: 4, trim: 'both' }), 'E3', 'E3');
|
|
387
|
+
t.is(toA1({ top: 2, bottom: 3, left: 4, right: 6, trim: 'both' }), 'E3.:.G4', 'E3.:.G4');
|
|
388
|
+
t.is(toA1({ top: 2, bottom: 3, trim: 'both' }), '3.:.4', '3.:.4');
|
|
389
|
+
t.is(toA1({ left: 4, right: 6, trim: 'both' }), 'E.:.G', 'E.:.G');
|
|
390
|
+
t.is(toA1({ top: 9, left: 0, right: 0, trim: 'tail' }), 'A10:.A', 'A10:.A');
|
|
391
|
+
t.is(toA1({ top: 9, left: 0, right: 0, trim: 'head' }), 'A10.:A', 'A10.:A');
|
|
392
|
+
t.is(toA1({ top: 9, left: 0, right: 0, trim: 'both' }), 'A10.:.A', 'A10.:.A');
|
|
393
|
+
|
|
346
394
|
t.end();
|
|
347
395
|
});
|
|
348
396
|
|
|
@@ -403,5 +451,19 @@ test('A1 utilities', t => {
|
|
|
403
451
|
};
|
|
404
452
|
t.deepEqual(toAbsolute(relA1Range), absA1Range, 'toAbsolute');
|
|
405
453
|
t.deepEqual(toRelative(absA1Range), relA1Range, 'toRelative');
|
|
454
|
+
|
|
455
|
+
const relA1RangeT = {
|
|
456
|
+
top: 0, left: 0, bottom: 0, right: 0,
|
|
457
|
+
$top: false, $left: false, $bottom: false, $right: false,
|
|
458
|
+
trim: 'both'
|
|
459
|
+
};
|
|
460
|
+
const absA1RangeT = {
|
|
461
|
+
top: 0, left: 0, bottom: 0, right: 0,
|
|
462
|
+
$top: true, $left: true, $bottom: true, $right: true,
|
|
463
|
+
trim: 'both'
|
|
464
|
+
};
|
|
465
|
+
t.deepEqual(toAbsolute(relA1RangeT), absA1RangeT, 'toAbsolute');
|
|
466
|
+
t.deepEqual(toRelative(absA1RangeT), relA1RangeT, 'toRelative');
|
|
467
|
+
|
|
406
468
|
t.end();
|
|
407
469
|
});
|
package/lib/addTokenMeta.js
CHANGED
|
@@ -182,7 +182,7 @@ export function addTokenMeta (tokenlist, { sheetName = '', workbookName = '' } =
|
|
|
182
182
|
token.type === REF_STRUCT
|
|
183
183
|
) {
|
|
184
184
|
const ref = (token.type === REF_STRUCT)
|
|
185
|
-
? parseStructRef(token.value, {
|
|
185
|
+
? parseStructRef(token.value, { xlsx: true })
|
|
186
186
|
: parseA1Ref(token.value, { allowTernary: true, xlsx: true });
|
|
187
187
|
if (ref && (ref.range || ref.columns)) {
|
|
188
188
|
ref.source = token.value;
|
package/lib/addTokenMeta.spec.js
CHANGED
|
@@ -137,5 +137,17 @@ test('add extra meta to operators', t => {
|
|
|
137
137
|
{ index: 7, depth: 0, type: REF_STRUCT, value: 'table[#data]', groupId: 'fxg1' }
|
|
138
138
|
], { sheetName: 'Sheet1', workbookName: 'foo' }, { xlsx: true });
|
|
139
139
|
|
|
140
|
+
// trimmin should not affect range equivalency
|
|
141
|
+
t.isMetaTokens('=A1:B2*A1.:B2*A1:.B2*A1.:.B2', [
|
|
142
|
+
{ type: FX_PREFIX, value: '=', index: 0, depth: 0 },
|
|
143
|
+
{ type: REF_RANGE, value: 'A1:B2', index: 1, depth: 0, groupId: 'fxg1' },
|
|
144
|
+
{ type: OPERATOR, value: '*', index: 2, depth: 0 },
|
|
145
|
+
{ type: REF_RANGE, value: 'A1.:B2', index: 3, depth: 0, groupId: 'fxg1' },
|
|
146
|
+
{ type: OPERATOR, value: '*', index: 4, depth: 0 },
|
|
147
|
+
{ type: REF_RANGE, value: 'A1:.B2', index: 5, depth: 0, groupId: 'fxg1' },
|
|
148
|
+
{ type: OPERATOR, value: '*', index: 6, depth: 0 },
|
|
149
|
+
{ type: REF_RANGE, value: 'A1.:.B2', index: 7, depth: 0, groupId: 'fxg1' }
|
|
150
|
+
], { sheetName: 'Sheet1', workbookName: 'foo' }, { xlsx: true });
|
|
151
|
+
|
|
140
152
|
t.end();
|
|
141
153
|
});
|
package/lib/constants.js
CHANGED
package/lib/extraTypes.js
CHANGED
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
* @property {boolean | null} [$bottom] Signifies that bottom is a "locked" value
|
|
39
39
|
* @property {boolean | null} [$left] Signifies that left is a "locked" value
|
|
40
40
|
* @property {boolean | null} [$right] Signifies that right is a "locked" value
|
|
41
|
+
* @property {"head" | "tail" | "both"} [trim] Should empty rows and columns at the top/left or bottom/right be discarded when range is read?
|
|
41
42
|
*/
|
|
42
43
|
|
|
43
44
|
/**
|
package/lib/fixRanges.spec.js
CHANGED
|
@@ -97,6 +97,7 @@ test('fixRanges A1 addBounds', t => {
|
|
|
97
97
|
t.isFixed('=A:A1', '=A:A', opt);
|
|
98
98
|
t.isFixed('=A:A$1', '=A:A', opt);
|
|
99
99
|
t.isFixed('=A:$A$1', '=A:$A', opt);
|
|
100
|
+
t.isFixed('=A.:A', '=A.:A', opt);
|
|
100
101
|
// partials - bottom
|
|
101
102
|
t.isFixed('=A1:A', '=A:A', opt);
|
|
102
103
|
t.isFixed('=A1:Z', '=A:Z', opt);
|
|
@@ -108,6 +109,7 @@ test('fixRanges A1 addBounds', t => {
|
|
|
108
109
|
t.isFixed('=B2:B', '=B2:B1048576', opt);
|
|
109
110
|
t.isFixed('=A:A2', '=A2:A1048576', opt);
|
|
110
111
|
t.isFixed('=B:B2', '=B2:B1048576', opt);
|
|
112
|
+
t.isFixed('=B.:.B2', '=B2.:.B1048576', opt);
|
|
111
113
|
// flipped partials - bottom
|
|
112
114
|
t.isFixed('=A1:1', '=1:1', opt);
|
|
113
115
|
t.isFixed('=A1:4', '=1:4', opt);
|
|
@@ -119,6 +121,7 @@ test('fixRanges A1 addBounds', t => {
|
|
|
119
121
|
t.isFixed('=1:B1', '=B1:XFD1', opt);
|
|
120
122
|
t.isFixed('=B2:20', '=B2:XFD20', opt);
|
|
121
123
|
t.isFixed('=2:B20', '=B2:XFD20', opt);
|
|
124
|
+
t.isFixed('=2:.B20', '=B2:.XFD20', opt);
|
|
122
125
|
t.end();
|
|
123
126
|
});
|
|
124
127
|
|
package/lib/lexer.js
CHANGED
|
@@ -7,7 +7,9 @@ import {
|
|
|
7
7
|
STRING,
|
|
8
8
|
UNKNOWN,
|
|
9
9
|
WHITESPACE,
|
|
10
|
-
FUNCTION
|
|
10
|
+
FUNCTION,
|
|
11
|
+
OPERATOR_TRIM,
|
|
12
|
+
REF_RANGE
|
|
11
13
|
} from './constants.js';
|
|
12
14
|
import { lexers } from './lexerParts.js';
|
|
13
15
|
import { mergeRefTokens } from './mergeRefTokens.js';
|
|
@@ -75,6 +77,7 @@ export function getTokens (fx, tokenHandlers, options = {}) {
|
|
|
75
77
|
let pos = 0;
|
|
76
78
|
let letOrLambda = 0;
|
|
77
79
|
let unknownRC = 0;
|
|
80
|
+
const trimOps = [];
|
|
78
81
|
|
|
79
82
|
let tail0 = null; // last non-whitespace token
|
|
80
83
|
let tail1 = null; // penultimate non-whitespace token
|
|
@@ -95,6 +98,10 @@ export function getTokens (fx, tokenHandlers, options = {}) {
|
|
|
95
98
|
}
|
|
96
99
|
}
|
|
97
100
|
else {
|
|
101
|
+
if (token.type === OPERATOR_TRIM) {
|
|
102
|
+
trimOps.push(tokens.length);
|
|
103
|
+
token.type = UNKNOWN;
|
|
104
|
+
}
|
|
98
105
|
// push token as normally
|
|
99
106
|
tokens.push(token);
|
|
100
107
|
lastToken = token;
|
|
@@ -105,7 +112,7 @@ export function getTokens (fx, tokenHandlers, options = {}) {
|
|
|
105
112
|
}
|
|
106
113
|
};
|
|
107
114
|
|
|
108
|
-
if (
|
|
115
|
+
if (fx.at(0) === '=') {
|
|
109
116
|
const token = {
|
|
110
117
|
type: FX_PREFIX,
|
|
111
118
|
value: '=',
|
|
@@ -208,6 +215,21 @@ export function getTokens (fx, tokenHandlers, options = {}) {
|
|
|
208
215
|
fixRCNames(tokens);
|
|
209
216
|
}
|
|
210
217
|
|
|
218
|
+
// Any OPERATOR_TRIM tokens have been indexed already, they now need to be
|
|
219
|
+
// either turned into OPERATORs or UNKNOWNs. Trim operators are only allowed
|
|
220
|
+
// between two REF_RANGE tokens as they are not valid in expressions as full
|
|
221
|
+
// operators.
|
|
222
|
+
for (const index of trimOps) {
|
|
223
|
+
const before = tokens[index - 1];
|
|
224
|
+
const after = tokens[index - 1];
|
|
225
|
+
if (before && before.type === REF_RANGE && after && after.type === REF_RANGE) {
|
|
226
|
+
tokens[index].type = OPERATOR;
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
tokens[index].type = UNKNOWN;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
211
233
|
if (mergeRefs) {
|
|
212
234
|
return mergeRefTokens(tokens);
|
|
213
235
|
}
|
package/lib/lexer.spec.js
CHANGED
|
@@ -969,6 +969,21 @@ test('tokenize A1 style references', t => {
|
|
|
969
969
|
{ type: REF_RANGE, value: 'A10:A20' }
|
|
970
970
|
]);
|
|
971
971
|
|
|
972
|
+
t.isTokens('=A10.:A20', [
|
|
973
|
+
{ type: FX_PREFIX, value: '=' },
|
|
974
|
+
{ type: REF_RANGE, value: 'A10.:A20' }
|
|
975
|
+
]);
|
|
976
|
+
|
|
977
|
+
t.isTokens('=A10:.A20', [
|
|
978
|
+
{ type: FX_PREFIX, value: '=' },
|
|
979
|
+
{ type: REF_RANGE, value: 'A10:.A20' }
|
|
980
|
+
]);
|
|
981
|
+
|
|
982
|
+
t.isTokens('=A10.:.A20', [
|
|
983
|
+
{ type: FX_PREFIX, value: '=' },
|
|
984
|
+
{ type: REF_RANGE, value: 'A10.:.A20' }
|
|
985
|
+
]);
|
|
986
|
+
|
|
972
987
|
t.isTokens('=A10:E20', [
|
|
973
988
|
{ type: FX_PREFIX, value: '=' },
|
|
974
989
|
{ type: REF_RANGE, value: 'A10:E20' }
|
|
@@ -984,6 +999,21 @@ test('tokenize A1 style references', t => {
|
|
|
984
999
|
{ type: REF_BEAM, value: '5:5' }
|
|
985
1000
|
]);
|
|
986
1001
|
|
|
1002
|
+
t.isTokens('=5.:5', [
|
|
1003
|
+
{ type: FX_PREFIX, value: '=' },
|
|
1004
|
+
{ type: REF_BEAM, value: '5.:5' }
|
|
1005
|
+
]);
|
|
1006
|
+
|
|
1007
|
+
t.isTokens('=5:.5', [
|
|
1008
|
+
{ type: FX_PREFIX, value: '=' },
|
|
1009
|
+
{ type: REF_BEAM, value: '5:.5' }
|
|
1010
|
+
]);
|
|
1011
|
+
|
|
1012
|
+
t.isTokens('=5.:.5', [
|
|
1013
|
+
{ type: FX_PREFIX, value: '=' },
|
|
1014
|
+
{ type: REF_BEAM, value: '5.:.5' }
|
|
1015
|
+
]);
|
|
1016
|
+
|
|
987
1017
|
t.isTokens('=15:15', [
|
|
988
1018
|
{ type: FX_PREFIX, value: '=' },
|
|
989
1019
|
{ type: REF_BEAM, value: '15:15' }
|
|
@@ -994,6 +1024,21 @@ test('tokenize A1 style references', t => {
|
|
|
994
1024
|
{ type: REF_BEAM, value: 'H:H' }
|
|
995
1025
|
]);
|
|
996
1026
|
|
|
1027
|
+
t.isTokens('=H.:H', [
|
|
1028
|
+
{ type: FX_PREFIX, value: '=' },
|
|
1029
|
+
{ type: REF_BEAM, value: 'H.:H' }
|
|
1030
|
+
]);
|
|
1031
|
+
|
|
1032
|
+
t.isTokens('=H:.H', [
|
|
1033
|
+
{ type: FX_PREFIX, value: '=' },
|
|
1034
|
+
{ type: REF_BEAM, value: 'H:.H' }
|
|
1035
|
+
]);
|
|
1036
|
+
|
|
1037
|
+
t.isTokens('=H.:.H', [
|
|
1038
|
+
{ type: FX_PREFIX, value: '=' },
|
|
1039
|
+
{ type: REF_BEAM, value: 'H.:.H' }
|
|
1040
|
+
]);
|
|
1041
|
+
|
|
997
1042
|
t.isTokens('=AA:JJ', [
|
|
998
1043
|
{ type: FX_PREFIX, value: '=' },
|
|
999
1044
|
{ type: REF_BEAM, value: 'AA:JJ' }
|
|
@@ -1222,6 +1267,15 @@ test('tokenize A1 style references', t => {
|
|
|
1222
1267
|
{ type: REF_BEAM, value: 'B:B' }
|
|
1223
1268
|
], { mergeRefs: false });
|
|
1224
1269
|
|
|
1270
|
+
t.isTokens('=Sheet1!A.:.A:B.:.B', [
|
|
1271
|
+
{ type: FX_PREFIX, value: '=' },
|
|
1272
|
+
{ type: CONTEXT, value: 'Sheet1' },
|
|
1273
|
+
{ type: OPERATOR, value: '!' },
|
|
1274
|
+
{ type: REF_BEAM, value: 'A.:.A' },
|
|
1275
|
+
{ type: OPERATOR, value: ':' },
|
|
1276
|
+
{ type: REF_BEAM, value: 'B.:.B' }
|
|
1277
|
+
], { mergeRefs: false });
|
|
1278
|
+
|
|
1225
1279
|
t.isTokens('=Sheet1!#REF!:A1', [
|
|
1226
1280
|
{ type: FX_PREFIX, value: '=' },
|
|
1227
1281
|
{ type: CONTEXT, value: 'Sheet1' },
|
|
@@ -1832,3 +1886,68 @@ test('tokenize r and c as names within LET and LAMBDA calls', t => {
|
|
|
1832
1886
|
|
|
1833
1887
|
t.end();
|
|
1834
1888
|
});
|
|
1889
|
+
|
|
1890
|
+
test('trim operators are not valid outside literal ranges', t => {
|
|
1891
|
+
// when not merging refs, trim ops are allowed between ranges
|
|
1892
|
+
t.isTokens('=Sheet1!A1.:.B2', [
|
|
1893
|
+
{ type: FX_PREFIX, value: '=' },
|
|
1894
|
+
{ type: CONTEXT, value: 'Sheet1' },
|
|
1895
|
+
{ type: OPERATOR, value: '!' },
|
|
1896
|
+
{ type: REF_RANGE, value: 'A1' },
|
|
1897
|
+
{ type: OPERATOR, value: '.:.' },
|
|
1898
|
+
{ type: REF_RANGE, value: 'B2' }
|
|
1899
|
+
], { mergeRefs: false });
|
|
1900
|
+
t.isTokens('A1:.B2', [
|
|
1901
|
+
{ type: REF_RANGE, value: 'A1' },
|
|
1902
|
+
{ type: OPERATOR, value: ':.' },
|
|
1903
|
+
{ type: REF_RANGE, value: 'B2' }
|
|
1904
|
+
], { mergeRefs: false });
|
|
1905
|
+
t.isTokens('A1.:B2', [
|
|
1906
|
+
{ type: REF_RANGE, value: 'A1' },
|
|
1907
|
+
{ type: OPERATOR, value: '.:' },
|
|
1908
|
+
{ type: REF_RANGE, value: 'B2' }
|
|
1909
|
+
], { mergeRefs: false });
|
|
1910
|
+
|
|
1911
|
+
t.isTokens('=Sheet1!A.:.A.:.B.:.B', [
|
|
1912
|
+
{ type: FX_PREFIX, value: '=' },
|
|
1913
|
+
{ type: REF_BEAM, value: 'Sheet1!A.:.A' },
|
|
1914
|
+
{ type: UNKNOWN, value: '.:.' },
|
|
1915
|
+
{ type: REF_BEAM, value: 'B.:.B' }
|
|
1916
|
+
]);
|
|
1917
|
+
|
|
1918
|
+
t.isTokens('=name1.:.name2', [
|
|
1919
|
+
{ type: FX_PREFIX, value: '=' },
|
|
1920
|
+
{ type: REF_NAMED, value: 'name1.' },
|
|
1921
|
+
{ type: UNKNOWN, value: ':.name2' }
|
|
1922
|
+
]);
|
|
1923
|
+
|
|
1924
|
+
t.isTokens('=OFFSET(A1,1,1).:.INDIRECT("A1")', [
|
|
1925
|
+
{ type: FX_PREFIX, value: '=' },
|
|
1926
|
+
{ type: FUNCTION, value: 'OFFSET' },
|
|
1927
|
+
{ type: OPERATOR, value: '(' },
|
|
1928
|
+
{ type: REF_RANGE, value: 'A1' },
|
|
1929
|
+
{ type: OPERATOR, value: ',' },
|
|
1930
|
+
{ type: NUMBER, value: '1' },
|
|
1931
|
+
{ type: OPERATOR, value: ',' },
|
|
1932
|
+
{ type: NUMBER, value: '1' },
|
|
1933
|
+
{ type: OPERATOR, value: ')' },
|
|
1934
|
+
{ type: UNKNOWN, value: '.:.INDIRECT' },
|
|
1935
|
+
{ type: OPERATOR, value: '(' },
|
|
1936
|
+
{ type: STRING, value: '"A1"' },
|
|
1937
|
+
{ type: OPERATOR, value: ')' }
|
|
1938
|
+
]);
|
|
1939
|
+
t.end();
|
|
1940
|
+
});
|
|
1941
|
+
|
|
1942
|
+
test('whitespace handling', t => {
|
|
1943
|
+
t.isTokens('\tA1\u00a0+\nB2\r', [
|
|
1944
|
+
{ type: WHITESPACE, value: '\t' },
|
|
1945
|
+
{ type: REF_RANGE, value: 'A1' },
|
|
1946
|
+
{ type: WHITESPACE, value: '\u00a0' },
|
|
1947
|
+
{ type: OPERATOR, value: '+' },
|
|
1948
|
+
{ type: NEWLINE, value: '\n' },
|
|
1949
|
+
{ type: REF_RANGE, value: 'B2' },
|
|
1950
|
+
{ type: WHITESPACE, value: '\r' }
|
|
1951
|
+
]);
|
|
1952
|
+
t.end();
|
|
1953
|
+
});
|
package/lib/lexerParts.js
CHANGED
|
@@ -15,7 +15,8 @@ import {
|
|
|
15
15
|
REF_TERNARY,
|
|
16
16
|
REF_STRUCT,
|
|
17
17
|
MAX_COLS,
|
|
18
|
-
MAX_ROWS
|
|
18
|
+
MAX_ROWS,
|
|
19
|
+
OPERATOR_TRIM
|
|
19
20
|
} from './constants.js';
|
|
20
21
|
import { fromCol } from './a1.js';
|
|
21
22
|
import { parseSRange } from './sr.js';
|
|
@@ -30,21 +31,23 @@ const re_STRING = /^"(?:""|[^"])*("|$)/;
|
|
|
30
31
|
const re_NUMBER = /^(?:\d+(\.\d+)?(?:[eE][+-]?\d+)?|\d+)/;
|
|
31
32
|
const re_CONTEXT = /^(?!!)(\[(?:[^\]])+\])?([0-9A-Za-z._¡¤§¨ª\u00ad¯-\uffff]+)?(?=!)/;
|
|
32
33
|
const re_CONTEXT_QUOTE = /^'(?:''|[^'])*('|$)(?=!)/;
|
|
34
|
+
const re_RANGE_TRIM = /^(\.:\.|\.:|:\.)/;
|
|
33
35
|
|
|
34
36
|
const rngPart = '\\$?[A-Z]{1,3}\\$?[1-9][0-9]{0,6}';
|
|
35
37
|
const colPart = '\\$?[A-Z]{1,3}';
|
|
36
38
|
const rowPart = '\\$?[1-9][0-9]{0,6}';
|
|
39
|
+
const rangeOp = '\\.?:\\.?';
|
|
37
40
|
const nextNotChar = '(?![a-z0-9_\\u00a1-\\uffff])';
|
|
38
|
-
const re_A1COL = new RegExp(`^${colPart}
|
|
39
|
-
const re_A1ROW = new RegExp(`^${rowPart}
|
|
41
|
+
const re_A1COL = new RegExp(`^${colPart}${rangeOp}${colPart}${nextNotChar}`, 'i');
|
|
42
|
+
const re_A1ROW = new RegExp(`^${rowPart}${rangeOp}${rowPart}${nextNotChar}`, 'i');
|
|
40
43
|
const re_A1RANGE = new RegExp(`^${rngPart}${nextNotChar}`, 'i');
|
|
41
|
-
const re_A1PARTIAL = new RegExp(`^((${colPart}|${rowPart})
|
|
44
|
+
const re_A1PARTIAL = new RegExp(`^((${colPart}|${rowPart})${rangeOp}${rngPart}|${rngPart}${rangeOp}(${colPart}|${rowPart}))(?![\\w($.])`, 'i');
|
|
42
45
|
const rPart = '(?:R(?:\\[[+-]?\\d+\\]|[1-9][0-9]{0,6})?)';
|
|
43
46
|
const cPart = '(?:C(?:\\[[+-]?\\d+\\]|[1-9][0-9]{0,4})?)';
|
|
44
|
-
const re_RCCOL = new RegExp(`^${cPart}(
|
|
45
|
-
const re_RCROW = new RegExp(`^${rPart}(
|
|
47
|
+
const re_RCCOL = new RegExp(`^${cPart}(${rangeOp}${cPart})?${nextNotChar}`, 'i');
|
|
48
|
+
const re_RCROW = new RegExp(`^${rPart}(${rangeOp}${rPart})?${nextNotChar}`, 'i');
|
|
46
49
|
const re_RCRANGE = new RegExp(`^(?:(?=[RC])${rPart}${cPart})${nextNotChar}`, 'i');
|
|
47
|
-
const re_RCPARTIAL = new RegExp(`^(${rPart}${cPart}(
|
|
50
|
+
const re_RCPARTIAL = new RegExp(`^(${rPart}${cPart}(${rangeOp}${cPart}|${rangeOp}${rPart})(?![[\\d])|(${rPart}|${cPart})(${rangeOp}${rPart}${cPart}))${nextNotChar}`, 'i');
|
|
48
51
|
|
|
49
52
|
// The advertized named ranges rules are a bit off from what Excel seems to do:
|
|
50
53
|
// in the "extended range" of chars, it looks like it allows most things above
|
|
@@ -169,6 +172,7 @@ function lexRange (str, options) {
|
|
|
169
172
|
}
|
|
170
173
|
if (t) {
|
|
171
174
|
reA1Nums.lastIndex = 0;
|
|
175
|
+
// XXX: can probably optimize this as we know letters can only be 3 at max
|
|
172
176
|
while ((m = reA1Nums.exec(t.value)) !== null) {
|
|
173
177
|
if (/^\d/.test(m[1])) { // row
|
|
174
178
|
if ((parseInt(m[1], 10) - 1) > MAX_ROWS) {
|
|
@@ -191,14 +195,17 @@ function lexRefOp (s, opts) {
|
|
|
191
195
|
? { type: OPERATOR, value: s[0] }
|
|
192
196
|
: null;
|
|
193
197
|
}
|
|
194
|
-
// in A1 mode we allow !
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
:
|
|
198
|
+
// in A1 mode we allow [ '!', ':', '.:', ':.', '.:.']
|
|
199
|
+
const m = /^(!|\.?:\.?)/.exec(s);
|
|
200
|
+
if (m) {
|
|
201
|
+
return { type: OPERATOR, value: m[1] };
|
|
202
|
+
}
|
|
203
|
+
return null;
|
|
198
204
|
}
|
|
199
205
|
|
|
200
206
|
export const lexers = [
|
|
201
207
|
makeHandler(ERROR, re_ERROR),
|
|
208
|
+
makeHandler(OPERATOR_TRIM, re_RANGE_TRIM),
|
|
202
209
|
makeHandler(OPERATOR, re_OPERATOR),
|
|
203
210
|
makeHandler(FUNCTION, re_FUNCTION),
|
|
204
211
|
makeHandler(BOOLEAN, re_BOOLEAN),
|
package/lib/mergeRefTokens.js
CHANGED
|
@@ -4,14 +4,23 @@ const END = '$';
|
|
|
4
4
|
|
|
5
5
|
const validRunsMerge = [
|
|
6
6
|
[ REF_RANGE, ':', REF_RANGE ],
|
|
7
|
+
[ REF_RANGE, '.:', REF_RANGE ],
|
|
8
|
+
[ REF_RANGE, ':.', REF_RANGE ],
|
|
9
|
+
[ REF_RANGE, '.:.', REF_RANGE ],
|
|
7
10
|
[ REF_RANGE ],
|
|
8
11
|
[ REF_BEAM ],
|
|
9
12
|
[ REF_TERNARY ],
|
|
10
13
|
[ CONTEXT, '!', REF_RANGE, ':', REF_RANGE ],
|
|
14
|
+
[ CONTEXT, '!', REF_RANGE, '.:', REF_RANGE ],
|
|
15
|
+
[ CONTEXT, '!', REF_RANGE, ':.', REF_RANGE ],
|
|
16
|
+
[ CONTEXT, '!', REF_RANGE, '.:.', REF_RANGE ],
|
|
11
17
|
[ CONTEXT, '!', REF_RANGE ],
|
|
12
18
|
[ CONTEXT, '!', REF_BEAM ],
|
|
13
19
|
[ CONTEXT, '!', REF_TERNARY ],
|
|
14
20
|
[ CONTEXT_QUOTE, '!', REF_RANGE, ':', REF_RANGE ],
|
|
21
|
+
[ CONTEXT_QUOTE, '!', REF_RANGE, '.:', REF_RANGE ],
|
|
22
|
+
[ CONTEXT_QUOTE, '!', REF_RANGE, ':.', REF_RANGE ],
|
|
23
|
+
[ CONTEXT_QUOTE, '!', REF_RANGE, '.:.', REF_RANGE ],
|
|
15
24
|
[ CONTEXT_QUOTE, '!', REF_RANGE ],
|
|
16
25
|
[ CONTEXT_QUOTE, '!', REF_BEAM ],
|
|
17
26
|
[ CONTEXT_QUOTE, '!', REF_TERNARY ],
|
|
@@ -95,6 +95,9 @@ test('mergeRefTokens cases', t => {
|
|
|
95
95
|
t.deepEqual(tokenize('[WB]Sheet1!A1:A', opts), [
|
|
96
96
|
{ type: REF_TERNARY, value: '[WB]Sheet1!A1:A' }
|
|
97
97
|
]);
|
|
98
|
+
t.deepEqual(tokenize('[WB]Sheet1!A1.:.C3', opts), [
|
|
99
|
+
{ type: REF_RANGE, value: '[WB]Sheet1!A1.:.C3' }
|
|
100
|
+
]);
|
|
98
101
|
|
|
99
102
|
t.deepEqual(tokenize('foo', opts), [
|
|
100
103
|
{ type: REF_NAMED, value: 'foo' }
|
package/lib/parseRef.js
CHANGED
|
@@ -71,7 +71,7 @@ function splitContextXlsx (contextString) {
|
|
|
71
71
|
|
|
72
72
|
const unquote = d => d.slice(1, -1).replace(/''/g, "'");
|
|
73
73
|
|
|
74
|
-
const pRangeOp = t => t && t.value === ':' && {};
|
|
74
|
+
const pRangeOp = t => t && (t.value === ':' || t.value === '.:' || t.value === ':.' || t.value === '.:.') && { operator: t.value };
|
|
75
75
|
const pRange = t => t && t.type === REF_RANGE && { r0: t.value };
|
|
76
76
|
const pPartial = t => t && t.type === REF_TERNARY && { r0: t.value };
|
|
77
77
|
const pRange2 = t => t && t.type === REF_RANGE && { r1: t.value };
|
|
@@ -125,13 +125,15 @@ export function parseRef (ref, opts) {
|
|
|
125
125
|
sheetName: '',
|
|
126
126
|
r0: '',
|
|
127
127
|
r1: '',
|
|
128
|
-
name: ''
|
|
128
|
+
name: '',
|
|
129
|
+
operator: ''
|
|
129
130
|
}
|
|
130
131
|
: {
|
|
131
132
|
context: [],
|
|
132
133
|
r0: '',
|
|
133
134
|
r1: '',
|
|
134
|
-
name: ''
|
|
135
|
+
name: '',
|
|
136
|
+
operator: ''
|
|
135
137
|
};
|
|
136
138
|
// discard the "="-prefix if it is there
|
|
137
139
|
if (tokens.length && tokens[0].type === FX_PREFIX) {
|
package/lib/parser.js
CHANGED
|
@@ -59,6 +59,7 @@ const refFunctions = [
|
|
|
59
59
|
'SINGLE',
|
|
60
60
|
'SWITCH',
|
|
61
61
|
'TAKE',
|
|
62
|
+
'TRIMRANGE',
|
|
62
63
|
'XLOOKUP'
|
|
63
64
|
];
|
|
64
65
|
|
|
@@ -138,7 +139,7 @@ function advance (expectNext = null, leftNode = null) {
|
|
|
138
139
|
// potential intersection operation (so don't allow operators as upcoming)
|
|
139
140
|
const haveRef = isReferenceNode(leftNode);
|
|
140
141
|
const possibleWSOp = haveRef && refIsUpcoming(false);
|
|
141
|
-
const nextIsCall = haveRef && tokens[tokenIndex + 1].value === '(';
|
|
142
|
+
const nextIsCall = haveRef && tokens[tokenIndex + 1] && tokens[tokenIndex + 1].value === '(';
|
|
142
143
|
if (!possibleWSOp && !nextIsCall) {
|
|
143
144
|
// ignore whitespace
|
|
144
145
|
while (isWhitespace(tokens[tokenIndex])) {
|
package/lib/parser.spec.js
CHANGED
|
@@ -70,6 +70,7 @@ test('parse ranges', t => {
|
|
|
70
70
|
t.isParsed('1:2', { type: 'ReferenceIdentifier', value: '1:2', kind: 'beam' });
|
|
71
71
|
t.isParsed('A1:2', { type: 'ReferenceIdentifier', value: 'A1:2', kind: 'range' });
|
|
72
72
|
t.isParsed('1:A2', { type: 'ReferenceIdentifier', value: '1:A2', kind: 'range' });
|
|
73
|
+
t.isParsed('A1.:.B2', { type: 'ReferenceIdentifier', value: 'A1.:.B2', kind: 'range' });
|
|
73
74
|
t.isParsed('Sheet!A1', { type: 'ReferenceIdentifier', value: 'Sheet!A1', kind: 'range' });
|
|
74
75
|
t.isParsed('[Workbook]Sheet!A1', { type: 'ReferenceIdentifier', value: '[Workbook]Sheet!A1', kind: 'range' });
|
|
75
76
|
t.isParsed('\'Sheet\'!A1', { type: 'ReferenceIdentifier', value: '\'Sheet\'!A1', kind: 'range' });
|
|
@@ -1181,3 +1182,15 @@ test('parser supports LET expressions', t => {
|
|
|
1181
1182
|
});
|
|
1182
1183
|
t.end();
|
|
1183
1184
|
});
|
|
1185
|
+
|
|
1186
|
+
test('parser whitespace handling', t => {
|
|
1187
|
+
t.isParsed('\tA1\u00a0+\nB2\r', {
|
|
1188
|
+
type: 'BinaryExpression',
|
|
1189
|
+
operator: '+',
|
|
1190
|
+
arguments: [
|
|
1191
|
+
{ type: 'ReferenceIdentifier', value: 'A1', kind: 'range' },
|
|
1192
|
+
{ type: 'ReferenceIdentifier', value: 'B2', kind: 'range' }
|
|
1193
|
+
]
|
|
1194
|
+
});
|
|
1195
|
+
t.end();
|
|
1196
|
+
});
|
package/lib/rc.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
** - R[1]C1:R[2]C2 will also work, but
|
|
7
7
|
** - R[1]C[1]:R2C2 doesn't have a direct rectangle represention without context.
|
|
8
8
|
*/
|
|
9
|
+
import { rangeOperator, trimDirection } from './a1.js';
|
|
9
10
|
import { MAX_ROWS, MAX_COLS } from './constants.js';
|
|
10
11
|
import { parseRef } from './parseRef.js';
|
|
11
12
|
import { stringifyPrefix, stringifyPrefixAlt } from './stringifyPrefix.js';
|
|
@@ -35,6 +36,8 @@ export function toR1C1 (range) {
|
|
|
35
36
|
const nullC0 = c0 == null;
|
|
36
37
|
let nullR1 = r1 == null;
|
|
37
38
|
let nullC1 = c1 == null;
|
|
39
|
+
const op = rangeOperator(range.trim);
|
|
40
|
+
const hasTrim = !!range.trim;
|
|
38
41
|
r0 = clamp($r0 ? 0 : -MAX_ROWS, r0 | 0, MAX_ROWS);
|
|
39
42
|
c0 = clamp($c0 ? 0 : -MAX_COLS, c0 | 0, MAX_COLS);
|
|
40
43
|
if (!nullR0 && nullR1 && !nullC0 && nullC1) {
|
|
@@ -52,14 +55,14 @@ export function toR1C1 (range) {
|
|
|
52
55
|
if ((allRows && !nullC0 && !nullC1) || (nullR0 && nullR1)) {
|
|
53
56
|
const a = toCoord(c0, $c0);
|
|
54
57
|
const b = toCoord(c1, $c1);
|
|
55
|
-
return 'C' + (a === b ? a : a + '
|
|
58
|
+
return 'C' + (a === b && !hasTrim ? a : a + op + 'C' + b);
|
|
56
59
|
}
|
|
57
60
|
// R:R
|
|
58
61
|
const allCols = c0 === 0 && c1 >= MAX_COLS;
|
|
59
62
|
if ((allCols && !nullR0 && !nullR1) || (nullC0 && nullC1)) {
|
|
60
63
|
const a = toCoord(r0, $r0);
|
|
61
64
|
const b = toCoord(r1, $r1);
|
|
62
|
-
return 'R' + (a === b ? a : a + '
|
|
65
|
+
return 'R' + (a === b && !hasTrim ? a : a + op + 'R' + b);
|
|
63
66
|
}
|
|
64
67
|
const s_r0 = toCoord(r0, $r0);
|
|
65
68
|
const s_r1 = toCoord(r1, $r1);
|
|
@@ -70,14 +73,14 @@ export function toR1C1 (range) {
|
|
|
70
73
|
return (
|
|
71
74
|
(nullR0 ? '' : 'R' + s_r0) +
|
|
72
75
|
(nullC0 ? '' : 'C' + s_c0) +
|
|
73
|
-
|
|
76
|
+
op +
|
|
74
77
|
(nullR1 ? '' : 'R' + s_r1) +
|
|
75
78
|
(nullC1 ? '' : 'C' + s_c1)
|
|
76
79
|
);
|
|
77
80
|
}
|
|
78
81
|
// RC:RC
|
|
79
82
|
if (s_r0 !== s_r1 || s_c0 !== s_c1) {
|
|
80
|
-
return 'R' + s_r0 + 'C' + s_c0 + '
|
|
83
|
+
return 'R' + s_r0 + 'C' + s_c0 + op + 'R' + s_r1 + 'C' + s_c1;
|
|
81
84
|
}
|
|
82
85
|
// RC
|
|
83
86
|
return 'R' + s_r0 + 'C' + s_c0;
|
|
@@ -140,8 +143,12 @@ function parseR1C1Part (ref) {
|
|
|
140
143
|
*/
|
|
141
144
|
export function fromR1C1 (rangeString) {
|
|
142
145
|
let final = null;
|
|
143
|
-
const [ part1, part2 ] = rangeString.split(
|
|
146
|
+
const [ part1, op, part2, overflow ] = rangeString.split(/(\.?:\.?)/);
|
|
147
|
+
if (overflow) {
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
144
150
|
const range = parseR1C1Part(part1);
|
|
151
|
+
const trim = trimDirection(!!op && op.at(0) === '.', !!op && op.at(-1) === '.');
|
|
145
152
|
if (range) {
|
|
146
153
|
const [ r0, c0, $r0, $c0 ] = range;
|
|
147
154
|
if (part2) {
|
|
@@ -209,7 +216,7 @@ export function fromR1C1 (rangeString) {
|
|
|
209
216
|
}
|
|
210
217
|
// range only - no second part
|
|
211
218
|
else if (r0 != null && c0 == null) {
|
|
212
|
-
|
|
219
|
+
final = {
|
|
213
220
|
r0: r0,
|
|
214
221
|
c0: null,
|
|
215
222
|
r1: r0,
|
|
@@ -221,7 +228,7 @@ export function fromR1C1 (rangeString) {
|
|
|
221
228
|
};
|
|
222
229
|
}
|
|
223
230
|
else if (r0 == null && c0 != null) {
|
|
224
|
-
|
|
231
|
+
final = {
|
|
225
232
|
r0: null,
|
|
226
233
|
c0: c0,
|
|
227
234
|
r1: null,
|
|
@@ -233,7 +240,7 @@ export function fromR1C1 (rangeString) {
|
|
|
233
240
|
};
|
|
234
241
|
}
|
|
235
242
|
else {
|
|
236
|
-
|
|
243
|
+
final = {
|
|
237
244
|
r0: r0 || 0,
|
|
238
245
|
c0: c0 || 0,
|
|
239
246
|
r1: r0 || 0,
|
|
@@ -245,6 +252,9 @@ export function fromR1C1 (rangeString) {
|
|
|
245
252
|
};
|
|
246
253
|
}
|
|
247
254
|
}
|
|
255
|
+
if (final && trim) {
|
|
256
|
+
final.trim = trim;
|
|
257
|
+
}
|
|
248
258
|
return final;
|
|
249
259
|
}
|
|
250
260
|
|
|
@@ -279,17 +289,19 @@ export function parseR1C1Ref (refString, { allowNamed = true, allowTernary = fal
|
|
|
279
289
|
const d = parseRef(refString, { allowNamed, allowTernary, xlsx, r1c1: true });
|
|
280
290
|
if (d && (d.r0 || d.name)) {
|
|
281
291
|
const range = d.r1
|
|
282
|
-
? fromR1C1(d.r0 +
|
|
292
|
+
? fromR1C1(d.r0 + d.operator + d.r1)
|
|
283
293
|
: fromR1C1(d.r0);
|
|
284
|
-
if (
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
return d;
|
|
294
|
+
if (range) {
|
|
295
|
+
return xlsx
|
|
296
|
+
? { workbookName: d.workbookName, sheetName: d.sheetName, range }
|
|
297
|
+
: { context: d.context, range };
|
|
289
298
|
}
|
|
290
|
-
|
|
291
|
-
return
|
|
299
|
+
if (d.name) {
|
|
300
|
+
return xlsx
|
|
301
|
+
? { workbookName: d.workbookName, sheetName: d.sheetName, name: d.name }
|
|
302
|
+
: { context: d.context, name: d.name };
|
|
292
303
|
}
|
|
304
|
+
return null;
|
|
293
305
|
}
|
|
294
306
|
return null;
|
|
295
307
|
}
|
package/lib/rc.spec.js
CHANGED
|
@@ -6,19 +6,8 @@ import { parseR1C1Ref, stringifyR1C1Ref, toR1C1 } from './rc.js';
|
|
|
6
6
|
Test.prototype.isRCEqual = function isTokens (expr, expect, opts) {
|
|
7
7
|
if (expect) {
|
|
8
8
|
expect = (opts?.xlsx)
|
|
9
|
-
? {
|
|
10
|
-
|
|
11
|
-
sheetName: '',
|
|
12
|
-
name: '',
|
|
13
|
-
range: null,
|
|
14
|
-
...expect
|
|
15
|
-
}
|
|
16
|
-
: {
|
|
17
|
-
context: [],
|
|
18
|
-
name: '',
|
|
19
|
-
range: null,
|
|
20
|
-
...expect
|
|
21
|
-
};
|
|
9
|
+
? { workbookName: '', sheetName: '', ...expect }
|
|
10
|
+
: { context: [], ...expect };
|
|
22
11
|
if (expect.range && typeof expect.range === 'object') {
|
|
23
12
|
// mix in some defaults so we don't have to write things out in full
|
|
24
13
|
expect.range = {
|
|
@@ -261,6 +250,43 @@ test('parse R1C1 ranges in XLSX mode', t => {
|
|
|
261
250
|
t.end();
|
|
262
251
|
});
|
|
263
252
|
|
|
253
|
+
test('R1C1 trimmed ranges', t => {
|
|
254
|
+
const locks = { $r0: true, $r1: true, $c0: true, $c1: true };
|
|
255
|
+
const opts = [ {}, { xlsx: true } ];
|
|
256
|
+
for (const opt of opts) {
|
|
257
|
+
t.isRCEqual('R[1]C[1]:R[2]C[2]', { range: { r0: 1, r1: 2, c0: 1, c1: 2 } }, opt);
|
|
258
|
+
t.isRCEqual('R[1]C[1].:R[2]C[2]', { range: { r0: 1, r1: 2, c0: 1, c1: 2, trim: 'head' } }, opt);
|
|
259
|
+
t.isRCEqual('R[1]C[1]:.R[2]C[2]', { range: { r0: 1, r1: 2, c0: 1, c1: 2, trim: 'tail' } }, opt);
|
|
260
|
+
t.isRCEqual('R[1]C[1].:.R[2]C[2]', { range: { r0: 1, r1: 2, c0: 1, c1: 2, trim: 'both' } }, opt);
|
|
261
|
+
|
|
262
|
+
t.isRCEqual('R2C2:R3C3', { range: { r0: 1, r1: 2, c0: 1, c1: 2, ...locks } }, opt);
|
|
263
|
+
t.isRCEqual('R2C2.:R3C3', { range: { r0: 1, r1: 2, c0: 1, c1: 2, trim: 'head', ...locks } }, opt);
|
|
264
|
+
t.isRCEqual('R2C2:.R3C3', { range: { r0: 1, r1: 2, c0: 1, c1: 2, trim: 'tail', ...locks } }, opt);
|
|
265
|
+
t.isRCEqual('R2C2.:.R3C3', { range: { r0: 1, r1: 2, c0: 1, c1: 2, trim: 'both', ...locks } }, opt);
|
|
266
|
+
|
|
267
|
+
t.isRCEqual('C[1]:C[2]', { range: { c0: 1, c1: 2 } }, opt);
|
|
268
|
+
t.isRCEqual('C[1].:C[2]', { range: { c0: 1, c1: 2, trim: 'head' } }, opt);
|
|
269
|
+
t.isRCEqual('C[1]:.C[2]', { range: { c0: 1, c1: 2, trim: 'tail' } }, opt);
|
|
270
|
+
t.isRCEqual('C[1].:.C[2]', { range: { c0: 1, c1: 2, trim: 'both' } }, opt);
|
|
271
|
+
|
|
272
|
+
t.isRCEqual('R[10]:R[10]', { range: { r0: 10, r1: 10 } }, opt);
|
|
273
|
+
t.isRCEqual('R[10].:R[10]', { range: { r0: 10, r1: 10, trim: 'head' } }, opt);
|
|
274
|
+
t.isRCEqual('R[10]:.R[10]', { range: { r0: 10, r1: 10, trim: 'tail' } }, opt);
|
|
275
|
+
t.isRCEqual('R[10].:.R[10]', { range: { r0: 10, r1: 10, trim: 'both' } }, opt);
|
|
276
|
+
|
|
277
|
+
t.isRCEqual('R[2]C[2]:R[4]', null, { ...opt });
|
|
278
|
+
t.isRCEqual('R[2]C[2]:C[4]', null, { ...opt });
|
|
279
|
+
t.isRCEqual('R[2]C[2].:.R[4]', null, { ...opt });
|
|
280
|
+
t.isRCEqual('R[2]C[2].:.C[4]', null, { ...opt });
|
|
281
|
+
|
|
282
|
+
t.isRCEqual('R[2]C[2]:R[4]', { range: { r0: 2, r1: 4, c0: 2 } }, { allowTernary: true, ...opt });
|
|
283
|
+
t.isRCEqual('R[2]C[2]:C[4]', { range: { r0: 2, c0: 2, c1: 4 } }, { allowTernary: true, ...opt });
|
|
284
|
+
t.isRCEqual('R[2]C[2].:.R[4]', { range: { r0: 2, r1: 4, c0: 2, trim: 'both' } }, { allowTernary: true, ...opt });
|
|
285
|
+
t.isRCEqual('R[2]C[2].:.C[4]', { range: { r0: 2, c0: 2, c1: 4, trim: 'both' } }, { allowTernary: true, ...opt });
|
|
286
|
+
}
|
|
287
|
+
t.end();
|
|
288
|
+
});
|
|
289
|
+
|
|
264
290
|
test('R1C1 serialization', t => {
|
|
265
291
|
// ray
|
|
266
292
|
t.isR1C1Rendered({ r0: 0, c0: 0, r1: 0, c1: MAX_COLS }, 'R');
|
|
@@ -317,6 +343,19 @@ test('R1C1 serialization', t => {
|
|
|
317
343
|
t.isR1C1Rendered({ r0: -15e5, c0: 0, r1: 15e5, c1: 0 }, 'R[-1048575]C:R[1048575]C');
|
|
318
344
|
t.isR1C1Rendered({ r0: 0.5, c0: 0.5, r1: 0.5, c1: 0.5, ...abs }, 'R1C1');
|
|
319
345
|
t.isR1C1Rendered({ r0: 0.5, c0: 0.5, r1: 0.5, c1: 0.5 }, 'RC');
|
|
346
|
+
// trimming
|
|
347
|
+
t.isR1C1Rendered({ r0: 1, c0: 1, r1: 2, c1: 2 }, 'R[1]C[1]:R[2]C[2]');
|
|
348
|
+
t.isR1C1Rendered({ r0: 1, c0: 1, r1: 2, c1: 2, trim: 'head' }, 'R[1]C[1].:R[2]C[2]');
|
|
349
|
+
t.isR1C1Rendered({ r0: 1, c0: 1, r1: 2, c1: 2, trim: 'tail' }, 'R[1]C[1]:.R[2]C[2]');
|
|
350
|
+
t.isR1C1Rendered({ r0: 1, c0: 1, r1: 2, c1: 2, trim: 'both' }, 'R[1]C[1].:.R[2]C[2]');
|
|
351
|
+
t.isR1C1Rendered({ r0: 1, c0: 1, r1: 1, c1: 1, trim: 'both' }, 'R[1]C[1]');
|
|
352
|
+
t.isR1C1Rendered({ r0: 1, r1: 1 }, 'R[1]');
|
|
353
|
+
t.isR1C1Rendered({ r0: 1, r1: 1, trim: 'head' }, 'R[1].:R[1]');
|
|
354
|
+
t.isR1C1Rendered({ r0: 1, r1: 1, trim: 'both' }, 'R[1].:.R[1]');
|
|
355
|
+
t.isR1C1Rendered({ c0: 1, c1: 1 }, 'C[1]');
|
|
356
|
+
t.isR1C1Rendered({ c0: 1, c1: 1, trim: 'tail' }, 'C[1]:.C[1]');
|
|
357
|
+
t.isR1C1Rendered({ c0: 1, c1: 1, trim: 'both' }, 'C[1].:.C[1]');
|
|
358
|
+
t.isR1C1Rendered({ r0: -5, c0: -2, c1: -2, trim: 'both' }, 'R[-5]C[-2].:.C[-2]');
|
|
320
359
|
t.end();
|
|
321
360
|
});
|
|
322
361
|
|
package/lib/sr.spec.js
CHANGED
|
@@ -278,7 +278,7 @@ test('structured references parse and serialize in xlsx mode', t => {
|
|
|
278
278
|
t.end();
|
|
279
279
|
});
|
|
280
280
|
|
|
281
|
-
test
|
|
281
|
+
test('longform serialize (in xlsx mode)', t => {
|
|
282
282
|
// thisRow should have no effect when parsing
|
|
283
283
|
t.isSREqual('Table2[[#This Row],[col1]]', {
|
|
284
284
|
table: 'Table2',
|
package/lib/stringifyPrefix.js
CHANGED
|
@@ -10,7 +10,7 @@ export function stringifyPrefix (ref) {
|
|
|
10
10
|
if (scope) {
|
|
11
11
|
const part = (nth % 2) ? '[' + scope + ']' : scope;
|
|
12
12
|
pre = part + pre;
|
|
13
|
-
quote += reBannedChars.test(scope);
|
|
13
|
+
quote += +reBannedChars.test(scope);
|
|
14
14
|
nth++;
|
|
15
15
|
}
|
|
16
16
|
}
|
|
@@ -26,11 +26,11 @@ export function stringifyPrefixAlt (ref) {
|
|
|
26
26
|
const { workbookName, sheetName } = ref;
|
|
27
27
|
if (workbookName) {
|
|
28
28
|
pre += '[' + workbookName + ']';
|
|
29
|
-
quote += reBannedChars.test(workbookName);
|
|
29
|
+
quote += +reBannedChars.test(workbookName);
|
|
30
30
|
}
|
|
31
31
|
if (sheetName) {
|
|
32
32
|
pre += sheetName;
|
|
33
|
-
quote += reBannedChars.test(sheetName);
|
|
33
|
+
quote += +reBannedChars.test(sheetName);
|
|
34
34
|
}
|
|
35
35
|
if (quote) {
|
|
36
36
|
pre = "'" + pre.replace(/'/g, "''") + "'";
|
|
@@ -199,3 +199,16 @@ test('translate works with xlsx mode references', t => {
|
|
|
199
199
|
]);
|
|
200
200
|
t.end();
|
|
201
201
|
});
|
|
202
|
+
|
|
203
|
+
test('translate works with trimmed ranges', t => {
|
|
204
|
+
const testExpr = (expr, anchor, expected) => {
|
|
205
|
+
const opts = { mergeRefs: true, xlsx: true, r1c1: true };
|
|
206
|
+
t.deepEqual(translateToA1(tokenize(expr, opts), anchor, opts), expected, expr);
|
|
207
|
+
};
|
|
208
|
+
testExpr('Sheet!R[-1]C[-1].:.RC*Sheet2!C[50].:.C[700]', 'B2', [
|
|
209
|
+
{ type: 'range', value: 'Sheet!A1.:.B2' },
|
|
210
|
+
{ type: 'operator', value: '*' },
|
|
211
|
+
{ type: 'range_beam', value: 'Sheet2!AZ.:.ZZ' }
|
|
212
|
+
]);
|
|
213
|
+
t.end();
|
|
214
|
+
});
|
|
@@ -182,3 +182,16 @@ test('translate works with xlsx mode', t => {
|
|
|
182
182
|
]);
|
|
183
183
|
t.end();
|
|
184
184
|
});
|
|
185
|
+
|
|
186
|
+
test('translate works with trimmed ranges', t => {
|
|
187
|
+
const testExpr = (expr, anchor, expected) => {
|
|
188
|
+
const opts = { mergeRefs: true, xlsx: true, r1c1: false };
|
|
189
|
+
t.deepEqual(translateToR1C1(tokenize(expr, opts), anchor, opts), expected, expr);
|
|
190
|
+
};
|
|
191
|
+
testExpr('Sheet!A1.:.B2*Sheet2!AZ.:.ZZ', 'B2', [
|
|
192
|
+
{ type: 'range', value: 'Sheet!R[-1]C[-1].:.RC' },
|
|
193
|
+
{ type: 'operator', value: '*' },
|
|
194
|
+
{ type: 'range_beam', value: 'Sheet2!C[50].:.C[700]' }
|
|
195
|
+
]);
|
|
196
|
+
t.end();
|
|
197
|
+
});
|
package/lib/translate.js
CHANGED
|
@@ -61,6 +61,9 @@ export function translateToR1C1 (formula, anchorCell, { xlsx = false, allowTerna
|
|
|
61
61
|
range.$r1 = d.$bottom;
|
|
62
62
|
range.$c0 = d.$left;
|
|
63
63
|
range.$c1 = d.$right;
|
|
64
|
+
if (d.trim) {
|
|
65
|
+
range.trim = d.trim;
|
|
66
|
+
}
|
|
64
67
|
ref.range = range;
|
|
65
68
|
token.value = stringifyR1C1Ref(ref, refOpts);
|
|
66
69
|
// if token includes offsets, those offsets are now likely wrong!
|
|
@@ -204,6 +207,9 @@ export function translateToA1 (formula, anchorCell, options = defaultOptions) {
|
|
|
204
207
|
range.right = c1;
|
|
205
208
|
range.$right = d.$c1;
|
|
206
209
|
}
|
|
210
|
+
if (d.trim) {
|
|
211
|
+
range.trim = d.trim;
|
|
212
|
+
}
|
|
207
213
|
if (isNaN(r0) || isNaN(r1) || isNaN(c0) || isNaN(c1)) {
|
|
208
214
|
// convert to ref error
|
|
209
215
|
token.type = ERROR;
|