Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- Added a new function: N. [#1585](https://github.com/handsontable/hyperformula/issues/1585)
- Added a new function: VALUE. [#1592](https://github.com/handsontable/hyperformula/issues/1592)

### Fixed

- Fixed `Error Map maximum size exceeded` error when loading big spreadsheets. [#1602](https://github.com/handsontable/hyperformula/issues/1602)

## [3.1.1] - 2025-12-18

### Fixed
Expand Down
2 changes: 1 addition & 1 deletion src/DependencyGraph/AddressMapping/AddressMapping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {Maybe} from '../../Maybe'
import {SheetBoundaries} from '../../Sheet'
import {ColumnsSpan, RowsSpan} from '../../Span'
import {ArrayFormulaVertex, DenseStrategy, ValueCellVertex} from '../index'
import {CellVertex} from '../Vertex'
import {CellVertex} from '../CellVertex'
import {ChooseAddressMapping} from './ChooseAddressMappingPolicy'
import {AddressMappingStrategy} from './AddressMappingStrategy'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import {SheetCellAddress, SimpleCellAddress} from '../../Cell'
import {Maybe} from '../../Maybe'
import {ColumnsSpan, RowsSpan} from '../../Span'
import {CellVertex} from '../Vertex'
import {CellVertex} from '../CellVertex'

export type AddressMappingStrategyConstructor = new (width: number, height: number) => AddressMappingStrategy

Expand Down
2 changes: 1 addition & 1 deletion src/DependencyGraph/AddressMapping/DenseStrategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import {SheetCellAddress, simpleCellAddress, SimpleCellAddress} from '../../Cell'
import {Maybe} from '../../Maybe'
import {ColumnsSpan, RowsSpan} from '../../Span'
import {CellVertex} from '../Vertex'
import {CellVertex} from '../CellVertex'
import {AddressMappingStrategy} from './AddressMappingStrategy'

/**
Expand Down
2 changes: 1 addition & 1 deletion src/DependencyGraph/AddressMapping/SparseStrategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import {SheetCellAddress, simpleCellAddress, SimpleCellAddress} from '../../Cell'
import {Maybe} from '../../Maybe'
import {ColumnsSpan, RowsSpan} from '../../Span'
import {CellVertex} from '../Vertex'
import {CellVertex} from '../CellVertex'
import {AddressMappingStrategy} from './AddressMappingStrategy'

/**
Expand Down
18 changes: 18 additions & 0 deletions src/DependencyGraph/CellVertex.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* @license
* Copyright (c) 2025 Handsoncode. All rights reserved.
*/

import {InterpreterValue} from '../interpreter/InterpreterValue'
import {Vertex} from './Vertex'

/**
* Represents vertex which keeps values of one or more cells
*/
export abstract class CellVertex extends Vertex {
public abstract getCellValue(): InterpreterValue

constructor() {
super()
}
}
32 changes: 16 additions & 16 deletions src/DependencyGraph/DependencyGraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ export class DependencyGraph {
}

public processCellDependencies(cellDependencies: CellDependency[], endVertex: Vertex) {
const endVertexId = this.graph.getNodeId(endVertex)
const endVertexId = endVertex.idInGraph

if (endVertexId === undefined) {
throw new Error('End vertex not found')
Expand All @@ -188,8 +188,8 @@ export class DependencyGraph {
this.rangeMapping.addOrUpdateVertex(rangeVertex)
}

this.graph.addNodeAndReturnId(rangeVertex)
const rangeVertexId = this.graph.getNodeId(rangeVertex)
this.graph.addNodeIfNotExists(rangeVertex)
const rangeVertexId = rangeVertex.idInGraph

if (rangeVertexId === undefined) {
throw new Error('Range vertex not found')
Expand Down Expand Up @@ -257,7 +257,7 @@ export class DependencyGraph {
}

const newVertex = new EmptyCellVertex()
const newVertexId = this.graph.addNodeAndReturnId(newVertex)
const newVertexId = this.graph.addNodeIfNotExists(newVertex)
this.addressMapping.setCell(address, newVertex)

return { vertex: newVertex, id: newVertexId }
Expand Down Expand Up @@ -567,12 +567,12 @@ export class DependencyGraph {
}

public addVertex(address: SimpleCellAddress, vertex: CellVertex): void {
this.graph.addNodeAndReturnId(vertex)
this.graph.addNodeIfNotExists(vertex)
this.addressMapping.setCell(address, vertex)
}

public addArrayVertex(address: SimpleCellAddress, vertex: ArrayFormulaVertex): void {
this.graph.addNodeAndReturnId(vertex)
this.graph.addNodeIfNotExists(vertex)
this.setAddressMappingForArrayVertex(vertex, address)
}

Expand Down Expand Up @@ -861,7 +861,7 @@ export class DependencyGraph {
}

private exchangeGraphNode(oldNode: Vertex, newNode: Vertex) {
this.graph.addNodeAndReturnId(newNode)
this.graph.addNodeIfNotExists(newNode)
const adjNodesStored = this.graph.adjacentNodes(oldNode)
this.removeVertex(oldNode)
adjNodesStored.forEach((adjacentNode) => {
Expand All @@ -876,30 +876,30 @@ export class DependencyGraph {
}

private correctInfiniteRangesDependency(address: SimpleCellAddress) {
const relevantInfiniteRanges = (this.graph.getInfiniteRanges())
.filter(({ node }) => (node as RangeVertex).range.addressInRange(address))
const relevantInfiniteRanges = this.graph.getInfiniteRanges()
.filter(node => (node as RangeVertex).range.addressInRange(address))

if (relevantInfiniteRanges.length <= 0) {
return
}

const { vertex, id: maybeVertexId } = this.fetchCellOrCreateEmpty(address)
const vertexId = maybeVertexId ?? this.graph.getNodeId(vertex)
const vertexId = maybeVertexId ?? vertex.idInGraph

if (vertexId === undefined) {
throw new Error('Vertex not found')
}

relevantInfiniteRanges.forEach(({ id }) => {
this.graph.addEdge(vertexId, id)
relevantInfiniteRanges.forEach((node) => {
this.graph.addEdge(vertexId, node)
})
}

private exchangeOrAddGraphNode(oldNode: Maybe<Vertex>, newNode: Vertex) {
if (oldNode) {
this.exchangeGraphNode(oldNode, newNode)
} else {
this.graph.addNodeAndReturnId(newNode)
this.graph.addNodeIfNotExists(newNode)
}
}

Expand Down Expand Up @@ -946,7 +946,7 @@ export class DependencyGraph {

private correctInfiniteRangesDependenciesByRangeVertex(vertex: RangeVertex) {
this.graph.getInfiniteRanges()
.forEach(({ id: infiniteRangeVertexId, node: infiniteRangeVertex }) => {
.forEach((infiniteRangeVertex) => {
const intersection = vertex.range.intersectionWith((infiniteRangeVertex as RangeVertex).range)

if (intersection === undefined) {
Expand All @@ -955,7 +955,7 @@ export class DependencyGraph {

intersection.addresses(this).forEach((address: SimpleCellAddress) => {
const { vertex, id } = this.fetchCellOrCreateEmpty(address)
this.graph.addEdge(id ?? vertex, infiniteRangeVertexId)
this.graph.addEdge(id ?? vertex, infiniteRangeVertex)
})
})
}
Expand Down Expand Up @@ -1069,7 +1069,7 @@ export class DependencyGraph {
while (find.smallerRangeVertex === undefined) {
const newRangeVertex = new RangeVertex(AbsoluteCellRange.spanFrom(currentRangeVertex.range.start, currentRangeVertex.range.width(), currentRangeVertex.range.height() - 1))
this.rangeMapping.addOrUpdateVertex(newRangeVertex)
this.graph.addNodeAndReturnId(newRangeVertex)
this.graph.addNodeIfNotExists(newRangeVertex)
const restRange = new AbsoluteCellRange(simpleCellAddress(currentRangeVertex.range.start.sheet, currentRangeVertex.range.start.col, currentRangeVertex.range.end.row), currentRangeVertex.range.end)
this.addAllFromRange(restRange, currentRangeVertex)
this.graph.addEdge(newRangeVertex, currentRangeVertex)
Expand Down
7 changes: 5 additions & 2 deletions src/DependencyGraph/EmptyCellVertex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@
* Copyright (c) 2025 Handsoncode. All rights reserved.
*/

import {CellVertex} from './CellVertex'
import {EmptyValue, EmptyValueType} from '../interpreter/InterpreterValue'

/**
* Represents singleton vertex bound to all empty cells
*/
export class EmptyCellVertex {
constructor() {}
export class EmptyCellVertex extends CellVertex {
constructor() {
super()
}

/**
* Retrieves cell value bound to that singleton
Expand Down
23 changes: 21 additions & 2 deletions src/DependencyGraph/FormulaVertex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,23 @@ import {LazilyTransformingAstService} from '../LazilyTransformingAstService'
import {Maybe} from '../Maybe'
import {Ast} from '../parser'
import {ColumnsSpan, RowsSpan} from '../Span'
import {CellVertex} from './CellVertex'

export abstract class FormulaVertex {

/**
* Abstract base class for vertices that contain formulas in the dependency graph.
*
* Stores formula AST, cell address, and version for lazy transformation support.
* Has two concrete implementations: {@link ScalarFormulaVertex} for single-cell formulas
* and {@link ArrayFormulaVertex} for array formulas that span multiple cells.
*/
export abstract class FormulaVertex extends CellVertex {
protected constructor(
protected formula: Ast,
protected cellAddress: SimpleCellAddress,
public version: number
) {
super()
}

public get width(): number {
Expand Down Expand Up @@ -79,6 +89,12 @@ export abstract class FormulaVertex {
public abstract isComputed(): boolean
}

/**
* Represents a formula vertex that produces an array result spanning multiple cells.
*
* Array formulas are transformed eagerly (unlike scalar formulas) and store their
* computed values in a {@link CellArray} structure.
*/
export class ArrayFormulaVertex extends FormulaVertex {
array: CellArray

Expand Down Expand Up @@ -221,7 +237,10 @@ export class ArrayFormulaVertex extends FormulaVertex {
}

/**
* Represents vertex which keeps formula
* Represents a formula vertex that produces a single scalar value.
*
* Unlike {@link ArrayFormulaVertex}, scalar formulas are transformed lazily
* and cache their computed value for retrieval.
*/
export class ScalarFormulaVertex extends FormulaVertex {
/** Most recently computed value of this formula. */
Expand Down
Loading
Loading