UNPKG

@borgar/fx

Version:

Utilities for working with Excel formulas

142 lines (115 loc) 4.41 kB
import { describe, test, expect } from 'vitest'; import { CONTEXT, FUNCTION, FX_PREFIX, OPERATOR, REF_RANGE, REF_BEAM, REF_NAMED, REF_TERNARY, UNKNOWN } from './constants.ts'; import { mergeRefTokens } from './mergeRefTokens.ts'; import { tokenize } from './tokenize.ts'; describe('mergeRefTokens', () => { test('merges reference tokens and preserves metadata', () => { const list = tokenize('=SUM([Wb1]Sheet1!A1:B2)', { mergeRefs: false, withLocation: true }); expect(list).toEqual([ { type: FX_PREFIX, value: '=', loc: [ 0, 1 ] }, { type: FUNCTION, value: 'SUM', loc: [ 1, 4 ] }, { type: OPERATOR, value: '(', loc: [ 4, 5 ] }, { type: CONTEXT, value: '[Wb1]Sheet1', loc: [ 5, 16 ] }, { type: OPERATOR, value: '!', loc: [ 16, 17 ] }, { type: REF_RANGE, value: 'A1', loc: [ 17, 19 ] }, { type: OPERATOR, value: ':', loc: [ 19, 20 ] }, { type: REF_RANGE, value: 'B2', loc: [ 20, 22 ] }, { type: OPERATOR, value: ')', loc: [ 22, 23 ] } ]); // set IDs on all tokens about to be joined list[3].id = 'id1'; list[4].id = 'id2'; list[5].id = 'id3'; list[6].id = 'id4'; list[7].id = 'id5'; const mergedList = mergeRefTokens(list); expect(mergedList).toEqual([ { type: FX_PREFIX, value: '=', loc: [ 0, 1 ] }, { type: FUNCTION, value: 'SUM', loc: [ 1, 4 ] }, { type: OPERATOR, value: '(', loc: [ 4, 5 ] }, { type: REF_RANGE, id: 'id5', // token has the id of the first one value: '[Wb1]Sheet1!A1:B2', loc: [ 5, 22 ] }, { type: OPERATOR, value: ')', loc: [ 22, 23 ] } ]); }); describe('tokenize with mergeRefs enabled', () => { const opts = { mergeRefs: true, allowTernary: true }; test('basic cell references', () => { expect(tokenize('A1', opts)).toEqual([ { type: REF_RANGE, value: 'A1' } ]); expect(tokenize('A1:A1', opts)).toEqual([ { type: REF_RANGE, value: 'A1:A1' } ]); }); test('beam references', () => { expect(tokenize('A:A', opts)).toEqual([ { type: REF_BEAM, value: 'A:A' } ]); }); test('ternary references', () => { expect(tokenize('A1:A', opts)).toEqual([ { type: REF_TERNARY, value: 'A1:A' } ]); }); test('quoted sheet references', () => { expect(tokenize('\'Sheet1\'!A1', opts)).toEqual([ { type: REF_RANGE, value: '\'Sheet1\'!A1' } ]); expect(tokenize('\'Sheet1\'!A:A', opts)).toEqual([ { type: REF_BEAM, value: '\'Sheet1\'!A:A' } ]); expect(tokenize('\'Sheet1\'!A1:A', opts)).toEqual([ { type: REF_TERNARY, value: '\'Sheet1\'!A1:A' } ]); }); test('unquoted sheet references', () => { expect(tokenize('Sheet1!A1', opts)).toEqual([ { type: REF_RANGE, value: 'Sheet1!A1' } ]); expect(tokenize('Sheet1!A:A', opts)).toEqual([ { type: REF_BEAM, value: 'Sheet1!A:A' } ]); expect(tokenize('Sheet1!A1:A', opts)).toEqual([ { type: REF_TERNARY, value: 'Sheet1!A1:A' } ]); }); test('workbook references', () => { expect(tokenize('[WB]Sheet1!A1', opts)).toEqual([ { type: REF_RANGE, value: '[WB]Sheet1!A1' } ]); expect(tokenize('[WB]Sheet1!A:A', opts)).toEqual([ { type: REF_BEAM, value: '[WB]Sheet1!A:A' } ]); expect(tokenize('[WB]Sheet1!A1:A', opts)).toEqual([ { type: REF_TERNARY, value: '[WB]Sheet1!A1:A' } ]); expect(tokenize('[WB]Sheet1!A1.:.C3', opts)).toEqual([ { type: REF_RANGE, value: '[WB]Sheet1!A1.:.C3' } ]); }); test('named references', () => { expect(tokenize('foo', opts)).toEqual([ { type: REF_NAMED, value: 'foo' } ]); expect(tokenize('\'quoted\'!foo', opts)).toEqual([ { type: REF_NAMED, value: '\'quoted\'!foo' } ]); expect(tokenize('Sheet1!foo', opts)).toEqual([ { type: REF_NAMED, value: 'Sheet1!foo' } ]); }); test('path references with different formats', () => { expect(tokenize('[path]!foo', opts)).toEqual([ { type: UNKNOWN, value: '[path]' }, { type: OPERATOR, value: '!' }, { type: REF_NAMED, value: 'foo' } ]); expect(tokenize('[path]prefix!foo', opts)).toEqual([ { type: REF_NAMED, value: '[path]prefix!foo' } ]); }); }); });