@borgar/fx
Version:
Utilities for working with Excel formulas
81 lines (75 loc) • 1.86 kB
text/typescript
import type {
ReferenceA1,
ReferenceStruct,
ReferenceR1C1,
ReferenceA1Xlsx,
ReferenceStructXlsx,
ReferenceR1C1Xlsx,
ReferenceName,
ReferenceNameXlsx
} from './types.ts';
const reBannedChars = /[^0-9A-Za-z._¡¤§¨ª\u00ad¯-\uffff]/;
// A1-XFD1048575 | R | C | RC
const reIsRangelike = /^(R|C|RC|[A-Z]{1,3}\d{1,7})$/i;
export function needQuotes (scope: string, yesItDoes = 0): number {
if (yesItDoes) {
return 1;
}
if (scope) {
if (reBannedChars.test(scope)) {
return 1;
}
if (reIsRangelike.test(scope)) {
return 1;
}
// Sheet/workbook names starting with a digit must be quoted in Excel to
// avoid ambiguity with numeric literals.
if (/^\d/.test(scope)) {
return 1;
}
}
return 0;
}
export function quotePrefix (prefix) {
return "'" + prefix.replace(/'/g, "''") + "'";
}
export function stringifyPrefix (
ref: ReferenceA1 | ReferenceName | ReferenceStruct | ReferenceR1C1
): string {
let pre = '';
let quote = 0;
let nth = 0;
const context = ref.context || [];
for (let i = context.length; i > -1; i--) {
const scope = context[i];
if (scope) {
const part = (nth % 2) ? '[' + scope + ']' : scope;
pre = part + pre;
quote += needQuotes(scope, quote);
nth++;
}
}
if (quote) {
pre = quotePrefix(pre);
}
return pre ? pre + '!' : pre;
}
export function stringifyPrefixXlsx (
ref: ReferenceA1Xlsx | ReferenceNameXlsx | ReferenceStructXlsx | ReferenceR1C1Xlsx
): string {
let pre = '';
let quote = 0;
const { workbookName, sheetName } = ref;
if (workbookName) {
pre += '[' + workbookName + ']';
quote += needQuotes(workbookName);
}
if (sheetName) {
pre += sheetName;
quote += needQuotes(sheetName);
}
if (quote) {
pre = quotePrefix(pre);
}
return pre ? pre + '!' : pre;
}