hyperformula
Version:
HyperFormula is a JavaScript engine for efficient processing of spreadsheet-like data and formulas
430 lines (428 loc) • 15 kB
JavaScript
"use strict";
exports.__esModule = true;
exports.WRONG_RANGE_SIZE = exports.AbsoluteRowRange = exports.AbsoluteColumnRange = exports.AbsoluteCellRange = void 0;
exports.isSimpleCellRange = isSimpleCellRange;
exports.simpleCellRange = void 0;
var _Cell = require("./Cell");
var _errors = require("./errors");
var _parser = require("./parser");
var _Span = require("./Span");
/**
* @license
* Copyright (c) 2025 Handsoncode. All rights reserved.
*/
const WRONG_RANGE_SIZE = exports.WRONG_RANGE_SIZE = 'AbsoluteCellRange: Wrong range size';
function isSimpleCellRange(obj) {
if (obj && (typeof obj === 'object' || typeof obj === 'function')) {
return 'start' in obj && (0, _Cell.isSimpleCellAddress)(obj.start) && 'end' in obj && (0, _Cell.isSimpleCellAddress)(obj.end);
} else {
return false;
}
}
const simpleCellRange = (start, end) => ({
start,
end
});
exports.simpleCellRange = simpleCellRange;
class AbsoluteCellRange {
constructor(start, end) {
if (start.sheet !== end.sheet) {
throw new _errors.SheetsNotEqual(start.sheet, end.sheet);
}
this.start = (0, _Cell.simpleCellAddress)(start.sheet, start.col, start.row);
this.end = (0, _Cell.simpleCellAddress)(end.sheet, end.col, end.row);
}
get sheet() {
return this.start.sheet;
}
static fromSimpleCellAddresses(start, end) {
if (start.sheet !== end.sheet) {
throw new _errors.SheetsNotEqual(start.sheet, end.sheet);
}
const width = end.col - start.col;
const height = end.row - start.row;
if (Number.isFinite(height) && Number.isFinite(width)) {
return new AbsoluteCellRange(start, end);
}
if (Number.isFinite(height)) {
return new AbsoluteRowRange(start.sheet, start.row, end.row);
}
return new AbsoluteColumnRange(start.sheet, start.col, end.col);
}
static fromAst(ast, baseAddress) {
if (ast.type === _parser.AstNodeType.CELL_RANGE) {
return AbsoluteCellRange.fromCellRange(ast, baseAddress);
} else if (ast.type === _parser.AstNodeType.COLUMN_RANGE) {
return AbsoluteColumnRange.fromColumnRange(ast, baseAddress);
} else {
return AbsoluteRowRange.fromRowRangeAst(ast, baseAddress);
}
}
static fromAstOrUndef(ast, baseAddress) {
try {
return AbsoluteCellRange.fromAst(ast, baseAddress);
} catch (_e) {
return undefined;
}
}
static fromCellRange(x, baseAddress) {
return new AbsoluteCellRange(x.start.toSimpleCellAddress(baseAddress), x.end.toSimpleCellAddress(baseAddress));
}
static spanFrom(topLeftCorner, width, height) {
const ret = AbsoluteCellRange.spanFromOrUndef(topLeftCorner, width, height);
if (ret === undefined) {
throw new Error(WRONG_RANGE_SIZE);
}
return ret;
}
static spanFromOrUndef(topLeftCorner, width, height) {
if (!Number.isFinite(width) && Number.isFinite(height)) {
if (topLeftCorner.col !== 0) {
return undefined;
}
return new AbsoluteRowRange(topLeftCorner.sheet, topLeftCorner.row, topLeftCorner.row + height - 1);
} else if (!Number.isFinite(height) && Number.isFinite(width)) {
if (topLeftCorner.row !== 0) {
return undefined;
}
return new AbsoluteColumnRange(topLeftCorner.sheet, topLeftCorner.col, topLeftCorner.col + width - 1);
} else if (Number.isFinite(height) && Number.isFinite(width)) {
return new AbsoluteCellRange(topLeftCorner, (0, _Cell.simpleCellAddress)(topLeftCorner.sheet, topLeftCorner.col + width - 1, topLeftCorner.row + height - 1));
}
return undefined;
}
static fromCoordinates(sheet, x1, y1, x2, y2) {
return new AbsoluteCellRange((0, _Cell.simpleCellAddress)(sheet, x1, y1), (0, _Cell.simpleCellAddress)(sheet, x2, y2));
}
isFinite() {
return Number.isFinite(this.size());
}
doesOverlap(other) {
if (this.start.sheet != other.start.sheet) {
return false;
}
if (this.end.row < other.start.row || this.start.row > other.end.row) {
return false;
}
if (this.end.col < other.start.col || this.start.col > other.end.col) {
return false;
}
return true;
}
addressInRange(address) {
if (this.sheet !== address.sheet) {
return false;
}
return this.start.row <= address.row && this.end.row >= address.row && this.start.col <= address.col && this.end.col >= address.col;
}
columnInRange(address) {
if (this.sheet !== address.sheet) {
return false;
}
return this.start.col <= address.col && this.end.col >= address.col;
}
rowInRange(address) {
if (this.sheet !== address.sheet) {
return false;
}
return this.start.row <= address.row && this.end.row >= address.row;
}
containsRange(range) {
return this.addressInRange(range.start) && this.addressInRange(range.end);
}
intersectionWith(other) {
if (this.sheet !== other.start.sheet) {
return undefined;
}
const startRow = Math.max(this.start.row, other.start.row);
const endRow = Math.min(this.end.row, other.end.row);
const startCol = Math.max(this.start.col, other.start.col);
const endCol = Math.min(this.end.col, other.end.col);
if (startRow > endRow || startCol > endCol) {
return undefined;
}
return new AbsoluteCellRange((0, _Cell.simpleCellAddress)(this.sheet, startCol, startRow), (0, _Cell.simpleCellAddress)(this.sheet, endCol, endRow));
}
includesRow(row) {
return this.start.row < row && this.end.row >= row;
}
includesColumn(column) {
return this.start.col < column && this.end.col >= column;
}
shiftByRows(numberOfRows) {
this.start.row += numberOfRows;
this.end.row += numberOfRows;
}
expandByRows(numberOfRows) {
this.end.row += numberOfRows;
}
shiftByColumns(numberOfColumns) {
this.start.col += numberOfColumns;
this.end.col += numberOfColumns;
}
shifted(byCols, byRows) {
return AbsoluteCellRange.spanFrom((0, _Cell.simpleCellAddress)(this.sheet, this.start.col + byCols, this.start.row + byRows), this.width(), this.height());
}
expandByColumns(numberOfColumns) {
this.end.col += numberOfColumns;
}
moveToSheet(toSheet) {
this.start.sheet = toSheet;
this.end.sheet = toSheet;
}
removeSpan(span) {
if (span instanceof _Span.RowsSpan) {
this.removeRows(span.start, span.end);
} else {
this.removeColumns(span.start, span.end);
}
}
shouldBeRemoved() {
return this.width() <= 0 || this.height() <= 0;
}
rangeWithSameWidth(startRow, numberOfRows) {
return AbsoluteCellRange.spanFrom((0, _Cell.simpleCellAddress)(this.sheet, this.start.col, startRow), this.width(), numberOfRows);
}
rangeWithSameHeight(startColumn, numberOfColumns) {
return AbsoluteCellRange.spanFrom((0, _Cell.simpleCellAddress)(this.sheet, startColumn, this.start.row), numberOfColumns, this.height());
}
toString() {
return `${this.start.sheet},${this.start.col},${this.start.row},${this.end.col},${this.end.row}`;
}
width() {
return this.end.col - this.start.col + 1;
}
height() {
return this.end.row - this.start.row + 1;
}
size() {
return this.height() * this.width();
}
arrayOfAddressesInRange() {
const result = [];
for (let y = 0; y < this.height(); ++y) {
result[y] = [];
for (let x = 0; x < this.width(); ++x) {
const value = (0, _Cell.simpleCellAddress)(this.sheet, this.start.col + x, this.start.row + y);
result[y].push(value);
}
}
return result;
}
withStart(newStart) {
return new AbsoluteCellRange(newStart, this.end);
}
sameDimensionsAs(other) {
return this.width() === other.width() && this.height() === other.height();
}
sameAs(other) {
return (0, _Cell.equalSimpleCellAddress)(this.start, other.start) && (0, _Cell.equalSimpleCellAddress)(this.end, other.end);
}
addressesArrayMap(dependencyGraph, op) {
const ret = [];
let currentRow = this.start.row;
while (currentRow <= this.effectiveEndRow(dependencyGraph)) {
let currentColumn = this.start.col;
const tmp = [];
while (currentColumn <= this.effectiveEndColumn(dependencyGraph)) {
tmp.push(op((0, _Cell.simpleCellAddress)(this.start.sheet, currentColumn, currentRow)));
currentColumn++;
}
ret.push(tmp);
currentRow++;
}
return ret;
}
addresses(dependencyGraph) {
const ret = [];
let currentRow = this.start.row;
const limitRow = this.effectiveEndRow(dependencyGraph);
const limitColumn = this.effectiveEndColumn(dependencyGraph);
while (currentRow <= limitRow) {
let currentColumn = this.start.col;
while (currentColumn <= limitColumn) {
ret.push((0, _Cell.simpleCellAddress)(this.start.sheet, currentColumn, currentRow));
currentColumn++;
}
currentRow++;
}
return ret;
}
*addressesWithDirection(right, bottom, dependencyGraph) {
if (right > 0) {
if (bottom > 0) {
let currentRow = this.effectiveEndRow(dependencyGraph);
while (currentRow >= this.start.row) {
let currentColumn = this.effectiveEndColumn(dependencyGraph);
while (currentColumn >= this.start.col) {
yield (0, _Cell.simpleCellAddress)(this.start.sheet, currentColumn, currentRow);
currentColumn -= 1;
}
currentRow -= 1;
}
} else {
let currentRow = this.start.row;
while (currentRow <= this.effectiveEndRow(dependencyGraph)) {
let currentColumn = this.effectiveEndColumn(dependencyGraph);
while (currentColumn >= this.start.col) {
yield (0, _Cell.simpleCellAddress)(this.start.sheet, currentColumn, currentRow);
currentColumn -= 1;
}
currentRow += 1;
}
}
} else {
if (bottom > 0) {
let currentRow = this.effectiveEndRow(dependencyGraph);
while (currentRow >= this.start.row) {
let currentColumn = this.start.col;
while (currentColumn <= this.effectiveEndColumn(dependencyGraph)) {
yield (0, _Cell.simpleCellAddress)(this.start.sheet, currentColumn, currentRow);
currentColumn += 1;
}
currentRow -= 1;
}
} else {
let currentRow = this.start.row;
while (currentRow <= this.effectiveEndRow(dependencyGraph)) {
let currentColumn = this.start.col;
while (currentColumn <= this.effectiveEndColumn(dependencyGraph)) {
yield (0, _Cell.simpleCellAddress)(this.start.sheet, currentColumn, currentRow);
currentColumn += 1;
}
currentRow += 1;
}
}
}
}
getAddress(col, row) {
if (col < 0 || row < 0 || row > this.height() - 1 || col > this.width() - 1) {
throw Error('Index out of bound');
}
return (0, _Cell.simpleCellAddress)(this.start.sheet, this.start.col + col, this.start.row + row);
}
exceedsSheetSizeLimits(maxColumns, maxRows) {
return this.end.col >= maxColumns || this.end.row >= maxRows;
}
effectiveEndColumn(_dependencyGraph) {
return this.end.col;
}
effectiveEndRow(_dependencyGraph) {
return this.end.row;
}
effectiveWidth(_dependencyGraph) {
return this.width();
}
effectiveHeight(_dependencyGraph) {
return this.height();
}
removeRows(rowStart, rowEnd) {
if (rowStart > this.end.row) {
return;
}
if (rowEnd < this.start.row) {
const numberOfRows = rowEnd - rowStart + 1;
return this.shiftByRows(-numberOfRows);
}
if (rowStart <= this.start.row) {
this.start.row = rowStart;
}
this.end.row -= Math.min(rowEnd, this.end.row) - rowStart + 1;
}
removeColumns(columnStart, columnEnd) {
if (columnStart > this.end.col) {
return;
}
if (columnEnd < this.start.col) {
const numberOfColumns = columnEnd - columnStart + 1;
return this.shiftByColumns(-numberOfColumns);
}
if (columnStart <= this.start.col) {
this.start.col = columnStart;
}
this.end.col -= Math.min(columnEnd, this.end.col) - columnStart + 1;
}
}
exports.AbsoluteCellRange = AbsoluteCellRange;
class AbsoluteColumnRange extends AbsoluteCellRange {
constructor(sheet, columnStart, columnEnd) {
super((0, _Cell.simpleCellAddress)(sheet, columnStart, 0), (0, _Cell.simpleCellAddress)(sheet, columnEnd, Number.POSITIVE_INFINITY));
}
static fromColumnRange(x, baseAddress) {
const start = x.start.toSimpleColumnAddress(baseAddress);
const end = x.end.toSimpleColumnAddress(baseAddress);
if (start.sheet !== end.sheet) {
throw new _errors.SheetsNotEqual(start.sheet, end.sheet);
}
return new AbsoluteColumnRange(start.sheet, start.col, end.col);
}
shouldBeRemoved() {
return this.width() <= 0;
}
shiftByRows(_numberOfRows) {
return;
}
expandByRows(_numberOfRows) {
return;
}
shifted(byCols, _byRows) {
return new AbsoluteColumnRange(this.sheet, this.start.col + byCols, this.end.col + byCols);
}
rangeWithSameHeight(startColumn, numberOfColumns) {
return new AbsoluteColumnRange(this.sheet, startColumn, startColumn + numberOfColumns - 1);
}
exceedsSheetSizeLimits(maxColumns, _maxRows) {
return this.end.col >= maxColumns;
}
effectiveEndRow(dependencyGraph) {
return this.effectiveHeight(dependencyGraph) - 1;
}
effectiveHeight(dependencyGraph) {
return dependencyGraph.getSheetHeight(this.sheet);
}
removeRows(_rowStart, _rowEnd) {
return;
}
}
exports.AbsoluteColumnRange = AbsoluteColumnRange;
class AbsoluteRowRange extends AbsoluteCellRange {
constructor(sheet, rowStart, rowEnd) {
super((0, _Cell.simpleCellAddress)(sheet, 0, rowStart), (0, _Cell.simpleCellAddress)(sheet, Number.POSITIVE_INFINITY, rowEnd));
}
static fromRowRangeAst(x, baseAddress) {
const start = x.start.toSimpleRowAddress(baseAddress);
const end = x.end.toSimpleRowAddress(baseAddress);
if (start.sheet !== end.sheet) {
throw new _errors.SheetsNotEqual(start.sheet, end.sheet);
}
return new AbsoluteRowRange(start.sheet, start.row, end.row);
}
shouldBeRemoved() {
return this.height() <= 0;
}
shiftByColumns(_numberOfColumns) {
return;
}
expandByColumns(_numberOfColumns) {
return;
}
shifted(byCols, byRows) {
return new AbsoluteRowRange(this.sheet, this.start.row + byRows, this.end.row + byRows);
}
rangeWithSameWidth(startRow, numberOfRows) {
return new AbsoluteRowRange(this.sheet, startRow, startRow + numberOfRows - 1);
}
exceedsSheetSizeLimits(_maxColumns, maxRows) {
return this.end.row >= maxRows;
}
effectiveEndColumn(dependencyGraph) {
return this.effectiveWidth(dependencyGraph) - 1;
}
effectiveWidth(dependencyGraph) {
return dependencyGraph.getSheetWidth(this.sheet);
}
removeColumns(_columnStart, _columnEnd) {
return;
}
}
exports.AbsoluteRowRange = AbsoluteRowRange;