@borgar/fx
Version:
Utilities for working with Excel formulas
105 lines (101 loc) • 3.17 kB
text/typescript
import { CONTEXT, CONTEXT_QUOTE } from '../constants.ts';
import type { Token } from '../types.ts';
const QUOT_SINGLE = 39; // '
const BR_OPEN = 91; // [
const BR_CLOSE = 93; // ]
const EXCL = 33; // !
// xlsx xml uses a variant of the syntax that has external references in
// bracets. Any of: [1]Sheet1!A1, '[1]Sheet one'!A1, [1]!named
export function lexContextQuoted (str: string, pos: number, options: { xlsx: boolean }): Token | undefined {
const c0 = str.charCodeAt(pos);
let br1: number;
let br2: number;
// quoted context: '(?:''|[^'])*('|$)(?=!)
if (c0 === QUOT_SINGLE) {
const start = pos;
pos++;
while (pos < str.length) {
const c = str.charCodeAt(pos);
if (c === BR_OPEN) {
if (br1) { return; } // only 1 allowed
br1 = pos;
}
else if (c === BR_CLOSE) {
if (br2) { return; } // only 1 allowed
br2 = pos;
}
else if (c === QUOT_SINGLE) {
pos++;
if (str.charCodeAt(pos) !== QUOT_SINGLE) {
let valid = br1 == null && br2 == null;
if (options.xlsx && (br1 === start + 1) && (br2 === pos - 2)) {
valid = true;
}
if ((br1 >= start + 1) && (br2 < pos - 2) && (br2 > br1 + 1)) {
valid = true;
}
if (valid && str.charCodeAt(pos) === EXCL) {
return { type: CONTEXT_QUOTE, value: str.slice(start, pos) };
}
return;
}
}
pos++;
}
}
}
// xlsx xml uses a variant of the syntax that has external references in
// bracets. Any of: [1]Sheet1!A1, '[1]Sheet one'!A1, [1]!named
export function lexContextUnquoted (str: string, pos: number, options: { xlsx: boolean }): Token | undefined {
const c0 = str.charCodeAt(pos);
let br1: number;
let br2: number;
if (c0 !== QUOT_SINGLE && c0 !== EXCL) {
const start = pos;
while (pos < str.length) {
const c = str.charCodeAt(pos);
if (c === BR_OPEN) {
if (br1) { return; } // only 1 allowed
br1 = pos;
}
else if (c === BR_CLOSE) {
if (br2) { return; } // only 1 allowed
br2 = pos;
}
else if (c === EXCL) {
let valid = br1 == null && br2 == null;
if (options.xlsx && (br1 === start) && (br2 === pos - 1)) {
valid = true;
}
if ((br1 >= start) && (br2 < pos - 1) && (br2 > br1 + 1)) {
valid = true;
}
if (valid) {
return { type: CONTEXT, value: str.slice(start, pos) };
}
}
else if (
(br1 == null || br2 != null) &&
// [0-9A-Za-z._¡¤§¨ª\u00ad¯-\uffff]
!(
(c >= 65 && c <= 90) || // A-Z
(c >= 97 && c <= 122) || // a-z
(c >= 48 && c <= 57) || // 0-9
(c === 46) || // .
(c === 95) || // _
(c === 161) || // ¡
(c === 164) || // ¤
(c === 167) || // §
(c === 168) || // ¨
(c === 170) || // ª
(c === 173) || // \u00ad
(c >= 175) // ¯-\uffff
)
) {
return;
}
// 0-9A-Za-z._¡¤§¨ª\u00ad¯-\uffff
pos++;
}
}
}