Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
52e45ef
Add unit test that reproduce the issue
sequba Nov 3, 2025
7d46318
Add changelog entry
sequba Nov 3, 2025
2f0d5d3
Generate solution
sequba Nov 5, 2025
0b1a3f8
Don't omitt end address in RemoveSheetTransformer
sequba Nov 5, 2025
01cd268
Refactor
sequba Nov 6, 2025
7840290
Different approach - no transformer
sequba Nov 13, 2025
87ede30
Merge branch 'develop' of github.com:handsontable/hyperformula into f…
sequba Nov 13, 2025
120df3c
Refactor
sequba Nov 16, 2025
e86e002
Refactor
sequba Nov 16, 2025
71148ac
Refactor
sequba Nov 16, 2025
7974eab
Add npm script for npm audit
sequba Nov 19, 2025
70c59aa
Add jsdoc comments
sequba Nov 19, 2025
f7b4363
Add more unit tests
sequba Nov 19, 2025
0584d8d
Switching to different approach. Revert changes in Operations.ts.
sequba Nov 20, 2025
d8cdb79
Refactr SheetMapping
sequba Nov 20, 2025
9402006
Add jsdocs to SheetMapping file
sequba Nov 20, 2025
a414d32
Fix linter in tests
sequba Nov 21, 2025
58140db
Make SheetMapping store reserved sheet names
sequba Nov 21, 2025
d328a72
Adjust graphComparator
sequba Nov 22, 2025
3d00519
Refactor addressRepresentationConverters.ts]
sequba Nov 23, 2025
b8c84e6
Refactor AddressMapping
sequba Nov 23, 2025
14023b2
Adjust evaluator to handle not-added sheets correctly
sequba Nov 23, 2025
fd49e9f
Fix adding sheet in AddressMapping
sequba Nov 23, 2025
7364bdb
Andjust tests for in ]compute-hash-from-tokens.spec.ts
sequba Nov 23, 2025
cbc75cb
Adjust tests in parser.spec.ts
sequba Nov 24, 2025
5f34c6f
Fix numeric aggregation plugin
sequba Nov 25, 2025
eb4af23
Make addSheet operation update the relevant dependency
sequba Nov 27, 2025
97356f7
Adjust tests in named-expressions.spec.ts
sequba Nov 28, 2025
cffcc7b
Adjust tests in mitting-events.spec.ts
sequba Dec 1, 2025
8ca4372
Add complex range test scenarios
sequba Dec 1, 2025
0cf6756
Remove vertices only if they are not referenced by existing sheets
sequba Dec 1, 2025
cee7881
Adjust tests in removing-sheet.spec.ts
sequba Dec 2, 2025
bdf2e97
Add unit tests for renaming sheet
sequba Dec 2, 2025
f232127
Handle rename sheet (issue with column/row ranges remains)
sequba Dec 4, 2025
8b689c9
Refactor: create SheetReferenceRegistrar
sequba Dec 4, 2025
2679230
Remove sheet from AddressMapping if nothing else depends on it
sequba Dec 4, 2025
5ca0a31
WIP
sequba Dec 4, 2025
63b3319
Remove unused functions
sequba Dec 4, 2025
e190a85
Remove unused constructor parameters
sequba Dec 5, 2025
f51e48d
Adjust range vertices after rename sheet
sequba Dec 5, 2025
a5d1b0b
Fix invalid test
sequba Dec 5, 2025
db9ebe0
Remove unused constructor param
sequba Dec 5, 2025
75b2b07
Update sheet strategy in AddressMapping if placeholder exists
sequba Dec 5, 2025
8d6d670
Refactor AddressMapping
sequba Dec 5, 2025
f20718a
Improve docs in SheetMapping
sequba Dec 5, 2025
30e4ae4
Refactor SheetMapping
sequba Dec 5, 2025
40778c8
Refactor NumericAggregationPlugin
sequba Dec 7, 2025
bc3c56e
Rename function to more descriptive name
sequba Dec 7, 2025
4422463
Refactor addressRepresentationConverters
sequba Dec 7, 2025
7d84527
Refactor
sequba Dec 7, 2025
c1935ea
Refactor Graph.ts
sequba Dec 7, 2025
a5c110d
Refactor SheetReferenceRegistrar.ts
sequba Dec 7, 2025
a2415c3
Refactor RangeMapping
sequba Dec 8, 2025
ba1deaf
Remove RemoveSheetTransformem which is not needed anymore
sequba Dec 8, 2025
73e8f4e
Rename FormulaCellVertex -> ScalarFormulaVertex and ArrayVertex -> Ar…
sequba Dec 8, 2025
4370a02
Refactor DependencyGraph
sequba Dec 8, 2025
db595e7
Refactor Operations
sequba Dec 8, 2025
e48dd82
Refactor DependencyGraph.removeSheet
sequba Dec 9, 2025
a3ef886
Make sure renameSheet handles dependency graph correctly
sequba Dec 9, 2025
aa82022
Refactor DependencyGraph.mergeSheets()
sequba Dec 9, 2025
45cf2b3
Refactor DependencyGraph
sequba Dec 9, 2025
1faab8f
Fix linter errors
sequba Dec 9, 2025
1d605b5
Hande undoAddSheet and redoAddSheet
sequba Dec 10, 2025
aae99c7
Hande undoRemoveSheet and redoRemoveSheet
sequba Dec 10, 2025
81f9e8d
Update changelog entry
sequba Dec 11, 2025
42da359
Add tests for undo/redo renameSheet()
sequba Dec 11, 2025
227423c
Handle undo for renameSheet()
sequba Dec 11, 2025
dbd3314
Apply suggestions from agent review
sequba Dec 11, 2025
8b75e80
Mor fixes after another agentic review
sequba Dec 11, 2025
8853e05
Update CellValueExporter tests to use SheetMapping instead of SheetIn…
sequba Dec 12, 2025
2be29b2
Configure eslint to allow null assertions in test files
sequba Dec 12, 2025
b92f8c6
Minor readibiklity fixes
sequba Dec 12, 2025
87e357a
Agent review fixes
sequba Dec 12, 2025
cf87298
Remove placeholder sheets when not needed enymore
sequba Dec 12, 2025
326c0fd
Apply suggestions after agentic code review of the test files
sequba Dec 13, 2025
902dfe1
Remove redundant tests
sequba Dec 13, 2025
682c274
Remove redundant tests
sequba Dec 13, 2025
aeada8d
Test the cleanup of placeholder sheets
sequba Dec 13, 2025
a0ec04f
Remove redundant tests
sequba Dec 13, 2025
388e0e9
Refactor tests for removing sheet
sequba Dec 13, 2025
8c1a86c
Reorgenize tests in rename-sheet.spec.ts
sequba Dec 13, 2025
9604fec
Reorganize tests in rename-sheet.spec.ts
sequba Dec 13, 2025
6142317
Remove redundant tests
sequba Dec 13, 2025
7c7d679
Refactor undo-redo.spec.ts
sequba Dec 14, 2025
8a6bcbb
Remove redundant newlines
sequba Dec 14, 2025
a25b6cd
More unit tests
sequba Dec 14, 2025
70bfce0
More tests
sequba Dec 14, 2025
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
8 changes: 7 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ module.exports = {
'jest/no-standalone-expect': 'warn',
'jest/no-test-prefixes': 'off',
'jest/prefer-to-be': 'warn',
'jest/prefer-to-have-length': 'warn',
'jest/prefer-to-have-length': 'off',
},
overrides: [
{
Expand All @@ -143,5 +143,11 @@ module.exports = {
'sort-keys': ['error', 'asc'],
}
},
{
files: ['**/*.spec.ts'],
rules: {
'@typescript-eslint/no-non-null-assertion': 'off',
}
}
],
}
2 changes: 1 addition & 1 deletion .github/workflows/audit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,4 @@ jobs:

- name: Run audit
run: |
npm audit --omit='dev'
npm run audit
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

### Fixed

- Fixed an issue where cells were not recalculated after adding, removing and renaming sheets. [#1116](https://github.com/handsontable/hyperformula/issues/1116)
- Fixed an issue where overwriting a non-computed cell caused the `Value of the formula cell is not computed` error. [#1194](https://github.com/handsontable/hyperformula/issues/1194)

## [3.1.0] - 2025-10-14
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
"test": "npm-run-all lint test:unit test:browser test:compatibility",
"test:unit": "cross-env NODE_ICU_DATA=node_modules/full-icu jest",
"test:watch": "cross-env NODE_ICU_DATA=node_modules/full-icu jest --watch",
"test:tdd": "cross-env NODE_ICU_DATA=node_modules/full-icu jest --watch named-expressions",
"test:tdd": "cross-env NODE_ICU_DATA=node_modules/full-icu jest --watch adding-sheet",
"test:coverage": "npm run test:unit -- --coverage",
"test:logMemory": "cross-env NODE_ICU_DATA=node_modules/full-icu jest --runInBand --logHeapUsage",
"test:unit.ci": "cross-env NODE_ICU_DATA=node_modules/full-icu node --expose-gc ./node_modules/jest/bin/jest --forceExit",
Expand All @@ -93,6 +93,7 @@
"benchmark:compare-benchmarks": "npm run tsnode test/performance/compare-benchmarks.ts",
"lint": "eslint . --ext .js,.ts",
"lint:fix": "eslint . --ext .js,.ts --fix",
"audit": "npm audit --omit=dev",
"clean": "rimraf coverage/ commonjs/ dist/ es/ languages/ lib/ typings/ test-jasmine/",
"compile": "tsc",
"check:licenses": "license-checker --production --excludePackages=\"[email protected]\" --onlyAllow=\"MIT; Apache-2.0; BSD-3-Clause; BSD-2-Clause; ISC; BSD; Unlicense\"",
Expand Down
12 changes: 8 additions & 4 deletions src/BuildEngineFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,17 @@ export class BuildEngineFactory {
throw new SheetSizeLimitExceededError()
}
const sheetId = sheetMapping.addSheet(sheetName)
addressMapping.autoAddSheet(sheetId, boundaries)
addressMapping.addSheetAndSetStrategyBasedOnBoundaries(sheetId, boundaries, { throwIfSheetAlreadyExists: true })
}
}

const parser = new ParserWithCaching(config, functionRegistry, sheetMapping.get)
const parser = new ParserWithCaching(
config,
functionRegistry,
dependencyGraph.sheetReferenceRegistrar.ensureSheetRegistered.bind(dependencyGraph.sheetReferenceRegistrar)
)
lazilyTransformingAstService.parser = parser
const unparser = new Unparser(config, buildLexerConfig(config), sheetMapping.fetchDisplayName, namedExpressions)
const unparser = new Unparser(config, sheetMapping, namedExpressions)
const dateTimeHelper = new DateTimeHelper(config)
const numberLiteralHelper = new NumberLiteralHelper(config)
const arithmeticHelper = new ArithmeticHelper(config, dateTimeHelper, numberLiteralHelper)
Expand All @@ -106,7 +110,7 @@ export class BuildEngineFactory {
const clipboardOperations = new ClipboardOperations(config, dependencyGraph, operations)
const crudOperations = new CrudOperations(config, operations, undoRedo, clipboardOperations, dependencyGraph, columnSearch, parser, cellContentParser, lazilyTransformingAstService, namedExpressions)

const exporter = new Exporter(config, namedExpressions, sheetMapping.fetchDisplayName, lazilyTransformingAstService)
const exporter = new Exporter(config, namedExpressions, sheetMapping, lazilyTransformingAstService)
const serialization = new Serialization(dependencyGraph, unparser, exporter)

const interpreter = new Interpreter(config, dependencyGraph, columnSearch, stats, arithmeticHelper, functionRegistry, namedExpressions, serialization, arraySizePredictor, dateTimeHelper)
Expand Down
15 changes: 10 additions & 5 deletions src/Cell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
* Copyright (c) 2025 Handsoncode. All rights reserved.
*/

import {ArrayVertex, CellVertex, FormulaCellVertex, ParsingErrorVertex, ValueCellVertex} from './DependencyGraph'
import {FormulaVertex} from './DependencyGraph/FormulaCellVertex'
import {ArrayFormulaVertex, CellVertex, ScalarFormulaVertex, ParsingErrorVertex, ValueCellVertex} from './DependencyGraph'
import {FormulaVertex} from './DependencyGraph/FormulaVertex'
import {ErrorMessage} from './error-message'
import {
EmptyValue,
Expand Down Expand Up @@ -59,14 +59,14 @@ export enum CellType {
}

export const getCellType = (vertex: Maybe<CellVertex>, address: SimpleCellAddress): CellType => {
if (vertex instanceof ArrayVertex) {
if (vertex instanceof ArrayFormulaVertex) {
if (vertex.isLeftCorner(address)) {
return CellType.ARRAYFORMULA
} else {
return CellType.ARRAY
}
}
if (vertex instanceof FormulaCellVertex || vertex instanceof ParsingErrorVertex) {
if (vertex instanceof ScalarFormulaVertex || vertex instanceof ParsingErrorVertex) {
return CellType.FORMULA
}
if (vertex instanceof ValueCellVertex) {
Expand Down Expand Up @@ -196,7 +196,12 @@ export interface SimpleCellAddress {
}

export const simpleCellAddress = (sheet: number, col: number, row: number): SimpleCellAddress => ({sheet, col, row})
export const invalidSimpleCellAddress = (address: SimpleCellAddress): boolean => (address.col < 0 || address.row < 0)

/**
* Checks if the column or row id is negative.
*/
export const isColOrRowInvalid = (address: SimpleCellAddress): boolean => (address.col < 0 || address.row < 0)

export const movedSimpleCellAddress = (address: SimpleCellAddress, toSheet: number, toRight: number, toBottom: number): SimpleCellAddress => {
return simpleCellAddress(toSheet, address.col + toRight, address.row + toBottom)
}
Expand Down
4 changes: 2 additions & 2 deletions src/ClipboardOperations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*/

import {AbsoluteCellRange} from './AbsoluteCellRange'
import {invalidSimpleCellAddress, simpleCellAddress, SimpleCellAddress} from './Cell'
import {isColOrRowInvalid, simpleCellAddress, SimpleCellAddress} from './Cell'
import {RawCellContent} from './CellContentParser'
import {Config} from './Config'
import {DependencyGraph} from './DependencyGraph'
Expand Down Expand Up @@ -119,7 +119,7 @@ export class ClipboardOperations {
return
}

if (invalidSimpleCellAddress(destinationLeftCorner) ||
if (isColOrRowInvalid(destinationLeftCorner) ||
!this.dependencyGraph.sheetMapping.hasSheetWithId(destinationLeftCorner.sheet)) {
throw new InvalidArgumentsError('a valid target address.')
}
Expand Down
40 changes: 23 additions & 17 deletions src/CrudOperations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*/

import {AbsoluteCellRange} from './AbsoluteCellRange'
import {invalidSimpleCellAddress, simpleCellAddress, SimpleCellAddress} from './Cell'
import {isColOrRowInvalid, simpleCellAddress, SimpleCellAddress} from './Cell'
import {CellContent, CellContentParser, RawCellContent} from './CellContentParser'
import {ClipboardCell, ClipboardOperations} from './ClipboardOperations'
import {Config} from './Config'
Expand Down Expand Up @@ -206,29 +206,35 @@ export class CrudOperations {
this.ensureItIsPossibleToAddSheet(name)
}
this.undoRedo.clearRedoStack()
const addedSheetName = this.operations.addSheet(name)
this.undoRedo.saveOperation(new AddSheetUndoEntry(addedSheetName))
return addedSheetName
const { sheetName, sheetId } = this.operations.addSheet(name)
this.undoRedo.saveOperation(new AddSheetUndoEntry(sheetName, sheetId))
return sheetName
}

public removeSheet(sheetId: number): void {
this.ensureScopeIdIsValid(sheetId)
this.undoRedo.clearRedoStack()
this.clipboardOperations.abortCut()
const originalName = this.sheetMapping.fetchDisplayName(sheetId)
const originalName = this.sheetMapping.getSheetNameOrThrowError(sheetId)
const oldSheetContent = this.operations.getSheetClipboardCells(sheetId)
const {version, scopedNamedExpressions} = this.operations.removeSheet(sheetId)
this.undoRedo.saveOperation(new RemoveSheetUndoEntry(originalName, sheetId, oldSheetContent, scopedNamedExpressions, version))
const scopedNamedExpressions = this.operations.removeSheet(sheetId)
this.undoRedo.saveOperation(new RemoveSheetUndoEntry(originalName, sheetId, oldSheetContent, scopedNamedExpressions))
}

public renameSheet(sheetId: number, newName: string): Maybe<string> {
this.ensureItIsPossibleToRenameSheet(sheetId, newName)
const oldName = this.operations.renameSheet(sheetId, newName)
if (oldName !== undefined) {
const { previousDisplayName, version, mergedPlaceholderSheetId } = this.operations.renameSheet(sheetId, newName)
if (previousDisplayName !== undefined) {
this.undoRedo.clearRedoStack()
this.undoRedo.saveOperation(new RenameSheetUndoEntry(sheetId, oldName, newName))
this.undoRedo.saveOperation(new RenameSheetUndoEntry(
sheetId,
previousDisplayName,
newName,
version,
mergedPlaceholderSheetId,
))
}
return oldName
return previousDisplayName
}

public clearSheet(sheetId: number): void {
Expand Down Expand Up @@ -495,8 +501,8 @@ export class CrudOperations {

if (
!this.sheetMapping.hasSheetWithId(sheet)
|| invalidSimpleCellAddress(sourceStart)
|| invalidSimpleCellAddress(targetStart)
|| isColOrRowInvalid(sourceStart)
|| isColOrRowInvalid(targetStart)
|| !isPositiveInteger(numberOfRows)
|| (targetRow <= startRow + numberOfRows && targetRow >= startRow)
) {
Expand All @@ -522,8 +528,8 @@ export class CrudOperations {

if (
!this.sheetMapping.hasSheetWithId(sheet)
|| invalidSimpleCellAddress(sourceStart)
|| invalidSimpleCellAddress(targetStart)
|| isColOrRowInvalid(sourceStart)
|| isColOrRowInvalid(targetStart)
|| !isPositiveInteger(numberOfColumns)
|| (targetColumn <= startColumn + numberOfColumns && targetColumn >= startColumn)
) {
Expand Down Expand Up @@ -552,14 +558,14 @@ export class CrudOperations {
throw new NoSheetWithIdError(sheetId)
}

const existingSheetId = this.sheetMapping.get(name)
const existingSheetId = this.sheetMapping.getSheetId(name)
if (existingSheetId !== undefined && existingSheetId !== sheetId) {
throw new SheetNameAlreadyTakenError(name)
}
}

public ensureItIsPossibleToChangeContent(address: SimpleCellAddress): void {
if (invalidSimpleCellAddress(address)) {
if (isColOrRowInvalid(address)) {
throw new InvalidAddressError(address)
}
if (!this.sheetMapping.hasSheetWithId(address.sheet)) {
Expand Down
Loading
Loading