UNPKG

@borgar/fx

Version:

Utilities for working with Excel formulas

167 lines (155 loc) 9.02 kB
import { describe, test, expect } from 'vitest'; import { FX_PREFIX, OPERATOR, NUMBER, REF_RANGE, REF_BEAM, FUNCTION, WHITESPACE, REF_STRUCT } from './constants.ts'; import { addTokenMeta } from './addTokenMeta.ts'; import { tokenize } from './tokenize.ts'; function isMetaTokens (expr: string, expected: any[], context?: any, opts?: any) { const actual = addTokenMeta(tokenize(expr, opts), context); if (actual.length === expected.length) { actual.forEach((d, i) => { const keys = Object.keys(d).concat(Object.keys(expected[i])); keys.forEach(key => { if (actual[i][key] === expected[i][key]) { delete actual[i][key]; delete expected[i][key]; } }); }); } expect(actual).toEqual(expected); } describe('add extra meta to operators', () => { test('parens should be grouped and tagged with depth', () => { isMetaTokens('=((1)+(1))', [ { index: 0, depth: 0, type: FX_PREFIX, value: '=' }, { index: 1, depth: 1, type: OPERATOR, value: '(', groupId: 'fxg3' }, { index: 2, depth: 2, type: OPERATOR, value: '(', groupId: 'fxg1' }, { index: 3, depth: 2, type: NUMBER, value: '1' }, { index: 4, depth: 2, type: OPERATOR, value: ')', groupId: 'fxg1' }, { index: 5, depth: 1, type: OPERATOR, value: '+' }, { index: 6, depth: 2, type: OPERATOR, value: '(', groupId: 'fxg2' }, { index: 7, depth: 2, type: NUMBER, value: '1' }, { index: 8, depth: 2, type: OPERATOR, value: ')', groupId: 'fxg2' }, { index: 9, depth: 1, type: OPERATOR, value: ')', groupId: 'fxg3' } ]); }); test('don\'t be fooled by imbalanced parens', () => { isMetaTokens('=)())', [ { index: 0, depth: 0, type: FX_PREFIX, value: '=' }, { index: 1, depth: 0, type: OPERATOR, value: ')', error: true }, { index: 2, depth: 1, type: OPERATOR, value: '(', groupId: 'fxg1' }, { index: 3, depth: 1, type: OPERATOR, value: ')', groupId: 'fxg1' }, { index: 4, depth: 0, type: OPERATOR, value: ')', error: true } ]); }); test('don\'t be fooled by nested curlys', () => { isMetaTokens('={{}}', [ { index: 0, depth: 0, type: FX_PREFIX, value: '=' }, { index: 1, depth: 1, type: OPERATOR, value: '{', groupId: 'fxg1' }, { index: 2, depth: 1, type: OPERATOR, value: '{', error: true }, { index: 3, depth: 1, type: OPERATOR, value: '}', groupId: 'fxg1' }, { index: 4, depth: 0, type: OPERATOR, value: '}', error: true } ]); }); test('group ranges if they are equivalent', () => { isMetaTokens("=B11,B11:B12,'Sheet11'!B11,SHEET1!$B11,sheet1!$b$11,A1:B11,[foo]Sheet1!B11,'[foo]Sheet1'!B11", [ { index: 0, depth: 0, type: FX_PREFIX, value: '=' }, { index: 1, depth: 0, type: REF_RANGE, value: 'B11', groupId: 'fxg1' }, { index: 2, depth: 0, type: OPERATOR, value: ',' }, { index: 3, depth: 0, type: REF_RANGE, value: 'B11:B12', groupId: 'fxg2' }, { index: 4, depth: 0, type: OPERATOR, value: ',' }, { index: 5, depth: 0, type: REF_RANGE, value: "'Sheet11'!B11", groupId: 'fxg3' }, { index: 6, depth: 0, type: OPERATOR, value: ',' }, { index: 7, depth: 0, type: REF_RANGE, value: 'SHEET1!$B11', groupId: 'fxg1' }, { index: 8, depth: 0, type: OPERATOR, value: ',' }, { index: 9, depth: 0, type: REF_RANGE, value: 'sheet1!$b$11', groupId: 'fxg1' }, { index: 10, depth: 0, type: OPERATOR, value: ',' }, { index: 11, depth: 0, type: REF_RANGE, value: 'A1:B11', groupId: 'fxg4' }, { index: 12, depth: 0, type: OPERATOR, value: ',' }, { index: 13, depth: 0, type: REF_RANGE, value: '[foo]Sheet1!B11', groupId: 'fxg1' }, { index: 14, depth: 0, type: OPERATOR, value: ',' }, { index: 15, depth: 0, type: REF_RANGE, value: "'[foo]Sheet1'!B11", groupId: 'fxg1' } ], { sheetName: 'Sheet1', workbookName: 'foo' }); }); test('group beam references', () => { isMetaTokens('=A:A,1:1,Sheet1!A:A:1:1,[foo]Sheet1!1:1', [ { index: 0, depth: 0, type: FX_PREFIX, value: '=' }, { index: 1, depth: 0, type: REF_BEAM, value: 'A:A', groupId: 'fxg1' }, { index: 2, depth: 0, type: OPERATOR, value: ',' }, { index: 3, depth: 0, type: REF_BEAM, value: '1:1', groupId: 'fxg2' }, { index: 4, depth: 0, type: OPERATOR, value: ',' }, { index: 5, depth: 0, type: REF_BEAM, value: 'Sheet1!A:A', groupId: 'fxg1' }, { index: 6, depth: 0, type: OPERATOR, value: ':' }, { index: 7, depth: 0, type: REF_BEAM, value: '1:1', groupId: 'fxg2' }, { index: 8, depth: 0, type: OPERATOR, value: ',' }, { index: 9, depth: 0, type: REF_BEAM, value: '[foo]Sheet1!1:1', groupId: 'fxg2' } ], { sheetName: 'Sheet1', workbookName: 'foo' }); }); test('complex function with nested grouping', () => { isMetaTokens('=SUM((1, 2), {3, 4})', [ { index: 0, depth: 0, type: FX_PREFIX, value: '=' }, { index: 1, depth: 0, type: FUNCTION, value: 'SUM' }, { index: 2, depth: 1, type: OPERATOR, value: '(', groupId: 'fxg3' }, { index: 3, depth: 2, type: OPERATOR, value: '(', groupId: 'fxg1' }, { index: 4, depth: 2, type: NUMBER, value: '1' }, { index: 5, depth: 2, type: OPERATOR, value: ',' }, { index: 6, depth: 2, type: WHITESPACE, value: ' ' }, { index: 7, depth: 2, type: NUMBER, value: '2' }, { index: 8, depth: 2, type: OPERATOR, value: ')', groupId: 'fxg1' }, { index: 9, depth: 1, type: OPERATOR, value: ',' }, { index: 10, depth: 1, type: WHITESPACE, value: ' ' }, { index: 11, depth: 2, type: OPERATOR, value: '{', groupId: 'fxg2' }, { index: 12, depth: 2, type: NUMBER, value: '3' }, { index: 13, depth: 2, type: OPERATOR, value: ',' }, { index: 14, depth: 2, type: WHITESPACE, value: ' ' }, { index: 15, depth: 2, type: NUMBER, value: '4' }, { index: 16, depth: 2, type: OPERATOR, value: '}', groupId: 'fxg2' }, { index: 17, depth: 1, type: OPERATOR, value: ')', groupId: 'fxg3' } ], { sheetName: 'Sheet1', workbookName: 'foo' }); }); test('group structured references', () => { isMetaTokens('=table[#all]+table[foobar]+table[[#All]]', [ { index: 0, depth: 0, type: FX_PREFIX, value: '=' }, { index: 1, depth: 0, type: REF_STRUCT, value: 'table[#all]', groupId: 'fxg1' }, { index: 2, depth: 0, type: OPERATOR, value: '+' }, { index: 3, depth: 0, type: REF_STRUCT, value: 'table[foobar]', groupId: 'fxg2' }, { index: 4, depth: 0, type: OPERATOR, value: '+' }, { index: 5, depth: 0, type: REF_STRUCT, value: 'table[[#All]]', groupId: 'fxg1' } ], { sheetName: 'Sheet1', workbookName: 'foo' }); }); test('group workbook references in xlsx mode', () => { isMetaTokens('=[foo]!A1+[foo]Sheet1!A1+Sheet1!A1+A1', [ { index: 0, depth: 0, type: FX_PREFIX, value: '=' }, { index: 1, depth: 0, type: REF_RANGE, value: '[foo]!A1', groupId: 'fxg1' }, { index: 2, depth: 0, type: OPERATOR, value: '+' }, { index: 3, depth: 0, type: REF_RANGE, value: '[foo]Sheet1!A1', groupId: 'fxg1' }, { index: 4, depth: 0, type: OPERATOR, value: '+' }, { index: 5, depth: 0, type: REF_RANGE, value: 'Sheet1!A1', groupId: 'fxg1' }, { index: 6, depth: 0, type: OPERATOR, value: '+' }, { index: 7, depth: 0, type: REF_RANGE, value: 'A1', groupId: 'fxg1' } ], { sheetName: 'Sheet1', workbookName: 'foo' }, { xlsx: true }); }); test('group structured references in xlsx mode', () => { isMetaTokens('=[foo]!table[#data]+[foo]Sheet1!table[#data]+Sheet1!table[#data]+table[#data]', [ { index: 0, depth: 0, type: FX_PREFIX, value: '=' }, { index: 1, depth: 0, type: REF_STRUCT, value: '[foo]!table[#data]', groupId: 'fxg1' }, { index: 2, depth: 0, type: OPERATOR, value: '+' }, { index: 3, depth: 0, type: REF_STRUCT, value: '[foo]Sheet1!table[#data]', groupId: 'fxg1' }, { index: 4, depth: 0, type: OPERATOR, value: '+' }, { index: 5, depth: 0, type: REF_STRUCT, value: 'Sheet1!table[#data]', groupId: 'fxg1' }, { index: 6, depth: 0, type: OPERATOR, value: '+' }, { index: 7, depth: 0, type: REF_STRUCT, value: 'table[#data]', groupId: 'fxg1' } ], { sheetName: 'Sheet1', workbookName: 'foo' }, { xlsx: true }); }); test('trimming should not affect range equivalency', () => { isMetaTokens('=A1:B2*A1.:B2*A1:.B2*A1.:.B2', [ { type: FX_PREFIX, value: '=', index: 0, depth: 0 }, { type: REF_RANGE, value: 'A1:B2', index: 1, depth: 0, groupId: 'fxg1' }, { type: OPERATOR, value: '*', index: 2, depth: 0 }, { type: REF_RANGE, value: 'A1.:B2', index: 3, depth: 0, groupId: 'fxg1' }, { type: OPERATOR, value: '*', index: 4, depth: 0 }, { type: REF_RANGE, value: 'A1:.B2', index: 5, depth: 0, groupId: 'fxg1' }, { type: OPERATOR, value: '*', index: 6, depth: 0 }, { type: REF_RANGE, value: 'A1.:.B2', index: 7, depth: 0, groupId: 'fxg1' } ], { sheetName: 'Sheet1', workbookName: 'foo' }, { xlsx: true }); }); });