UNPKG

hyperformula

Version:

HyperFormula is a JavaScript engine for efficient processing of spreadsheet-like data and formulas

216 lines (214 loc) 8.73 kB
"use strict"; exports.__esModule = true; exports.columnAddressFromString = exports.cellAddressFromString = void 0; exports.columnIndexToLabel = columnIndexToLabel; exports.rowAddressFromString = void 0; exports.sheetIndexToString = sheetIndexToString; exports.simpleCellRangeToString = exports.simpleCellRangeFromString = exports.simpleCellAddressToString = exports.simpleCellAddressFromString = void 0; var _AbsoluteCellRange = require("../AbsoluteCellRange"); var _Cell = require("../Cell"); var _CellAddress = require("./CellAddress"); var _ColumnAddress = require("./ColumnAddress"); var _parserConsts = require("./parser-consts"); var _RowAddress = require("./RowAddress"); /** * @license * Copyright (c) 2025 Handsoncode. All rights reserved. */ const addressRegex = new RegExp(`^(${_parserConsts.SHEET_NAME_PATTERN})?(\\${_parserConsts.ABSOLUTE_OPERATOR}?)([A-Za-z]+)(\\${_parserConsts.ABSOLUTE_OPERATOR}?)([0-9]+)$`); const columnRegex = new RegExp(`^(${_parserConsts.SHEET_NAME_PATTERN})?(\\${_parserConsts.ABSOLUTE_OPERATOR}?)([A-Za-z]+)$`); const rowRegex = new RegExp(`^(${_parserConsts.SHEET_NAME_PATTERN})?(\\${_parserConsts.ABSOLUTE_OPERATOR}?)([0-9]+)$`); const simpleSheetNameRegex = new RegExp(`^${_parserConsts.UNQUOTED_SHEET_NAME_PATTERN}$`); /** * Computes R0C0 representation of cell address based on it's string representation and base address. * * @param sheetMapping - mapping function needed to change name of a sheet to index * @param stringAddress - string representation of cell address, e.g., 'C64' * @param baseAddress - base address for R0C0 conversion * @returns object representation of address */ const cellAddressFromString = (sheetMapping, stringAddress, baseAddress) => { const result = addressRegex.exec(stringAddress); const col = columnLabelToIndex(result[6]); let sheet = extractSheetNumber(result, sheetMapping); if (sheet === undefined) { return undefined; } if (sheet === null) { sheet = undefined; } const row = Number(result[8]) - 1; if (result[5] === _parserConsts.ABSOLUTE_OPERATOR && result[7] === _parserConsts.ABSOLUTE_OPERATOR) { return _CellAddress.CellAddress.absolute(col, row, sheet); } else if (result[5] === _parserConsts.ABSOLUTE_OPERATOR) { return _CellAddress.CellAddress.absoluteCol(col, row - baseAddress.row, sheet); } else if (result[7] === _parserConsts.ABSOLUTE_OPERATOR) { return _CellAddress.CellAddress.absoluteRow(col - baseAddress.col, row, sheet); } else { return _CellAddress.CellAddress.relative(col - baseAddress.col, row - baseAddress.row, sheet); } }; exports.cellAddressFromString = cellAddressFromString; const columnAddressFromString = (sheetMapping, stringAddress, baseAddress) => { const result = columnRegex.exec(stringAddress); let sheet = extractSheetNumber(result, sheetMapping); if (sheet === undefined) { return undefined; } if (sheet === null) { sheet = undefined; } const col = columnLabelToIndex(result[6]); if (result[5] === _parserConsts.ABSOLUTE_OPERATOR) { return _ColumnAddress.ColumnAddress.absolute(col, sheet); } else { return _ColumnAddress.ColumnAddress.relative(col - baseAddress.col, sheet); } }; exports.columnAddressFromString = columnAddressFromString; const rowAddressFromString = (sheetMapping, stringAddress, baseAddress) => { const result = rowRegex.exec(stringAddress); let sheet = extractSheetNumber(result, sheetMapping); if (sheet === undefined) { return undefined; } if (sheet === null) { sheet = undefined; } const row = Number(result[6]) - 1; if (result[5] === _parserConsts.ABSOLUTE_OPERATOR) { return _RowAddress.RowAddress.absolute(row, sheet); } else { return _RowAddress.RowAddress.relative(row - baseAddress.row, sheet); } }; /** * Computes simple (absolute) address of a cell address based on its string representation. * - If sheet name is present in the string representation but is not present in sheet mapping, returns `undefined`. * - If sheet name is not present in the string representation, returns {@param contextSheetId} as sheet number. * * @param sheetMapping - mapping function needed to change name of a sheet to index * @param stringAddress - string representation of cell address, e.g., 'C64' * @param contextSheetId - sheet in context of which we should parse the address * @returns absolute representation of address, e.g., { sheet: 0, col: 1, row: 1 } */ exports.rowAddressFromString = rowAddressFromString; const simpleCellAddressFromString = (sheetMapping, stringAddress, contextSheetId) => { const regExpExecArray = addressRegex.exec(stringAddress); if (!regExpExecArray) { return undefined; } const col = columnLabelToIndex(regExpExecArray[6]); let sheet = extractSheetNumber(regExpExecArray, sheetMapping); if (sheet === undefined) { return undefined; } if (sheet === null) { sheet = contextSheetId; } const row = Number(regExpExecArray[8]) - 1; return (0, _Cell.simpleCellAddress)(sheet, col, row); }; exports.simpleCellAddressFromString = simpleCellAddressFromString; const simpleCellRangeFromString = (sheetMapping, stringAddress, contextSheetId) => { const split = stringAddress.split(_parserConsts.RANGE_OPERATOR); if (split.length !== 2) { return undefined; } const [startString, endString] = split; const start = simpleCellAddressFromString(sheetMapping, startString, contextSheetId); if (start === undefined) { return undefined; } const end = simpleCellAddressFromString(sheetMapping, endString, start.sheet); if (end === undefined) { return undefined; } if (start.sheet !== end.sheet) { return undefined; } return (0, _AbsoluteCellRange.simpleCellRange)(start, end); }; /** * Returns string representation of absolute address * If sheet index is not present in sheet mapping, returns undefined * * @param sheetIndexMapping - mapping function needed to change sheet index to sheet name * @param address - object representation of absolute address * @param sheetIndex - if is not equal with address sheet index, string representation will contain sheet name */ exports.simpleCellRangeFromString = simpleCellRangeFromString; const simpleCellAddressToString = (sheetIndexMapping, address, sheetIndex) => { const column = columnIndexToLabel(address.col); const sheetName = sheetIndexToString(address.sheet, sheetIndexMapping); if (sheetName === undefined) { return undefined; } if (sheetIndex !== address.sheet) { return `${sheetName}!${column}${address.row + 1}`; } else { return `${column}${address.row + 1}`; } }; exports.simpleCellAddressToString = simpleCellAddressToString; const simpleCellRangeToString = (sheetIndexMapping, address, sheetIndex) => { const startString = simpleCellAddressToString(sheetIndexMapping, address.start, sheetIndex); const endString = simpleCellAddressToString(sheetIndexMapping, address.end, address.start.sheet); if (startString === undefined || endString === undefined) { return undefined; } else { return `${startString}${_parserConsts.RANGE_OPERATOR}${endString}`; } }; /** * Convert column label to index * * @param columnStringRepresentation - column label (e.g., 'AAB') * @returns column index */ exports.simpleCellRangeToString = simpleCellRangeToString; function columnLabelToIndex(columnStringRepresentation) { if (columnStringRepresentation.length === 1) { return columnStringRepresentation.toUpperCase().charCodeAt(0) - 65; } else { return columnStringRepresentation.split('').reduce((currentColumn, nextLetter) => { return currentColumn * 26 + (nextLetter.toUpperCase().charCodeAt(0) - 64); }, 0) - 1; } } /** * Converts column index to label * * @param column - address to convert * @returns string representation, e.g., 'AAB' */ function columnIndexToLabel(column) { let result = ''; while (column >= 0) { result = String.fromCharCode(column % 26 + 97) + result; column = Math.floor(column / 26) - 1; } return result.toUpperCase(); } function sheetIndexToString(sheetId, sheetMappingFn) { let sheetName = sheetMappingFn(sheetId); if (sheetName === undefined) { return undefined; } if (simpleSheetNameRegex.test(sheetName)) { return sheetName; } else { sheetName = sheetName.replace(/'/g, "''"); return `'${sheetName}'`; } } function extractSheetNumber(regexResult, sheetMapping) { var _a; let maybeSheetName = (_a = regexResult[3]) !== null && _a !== void 0 ? _a : regexResult[2]; if (maybeSheetName) { maybeSheetName = maybeSheetName.replace(/''/g, "'"); return sheetMapping(maybeSheetName); } else { return null; } }