diff --git a/.eslintignore b/.eslintignore
index 1bec93b8c..37928812f 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -11,6 +11,7 @@ src/interpreter/plugin/3rdparty
*.config.js
karma.*
doc
+test/unit/_setupFiles/*.js
# Auto-generated directories
commonjs
@@ -25,4 +26,3 @@ test-jasmine
test-jest
typedoc
typings
-test/_setupFiles/*.js
diff --git a/.eslintrc.js b/.eslintrc.js
index b89b2641d..9b8544c84 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -90,7 +90,6 @@ module.exports = {
'jsdoc/empty-tags': 'warn',
'jsdoc/implements-on-classes': 'warn',
'jsdoc/multiline-blocks': 'warn',
- 'jsdoc/tag-lines': 'warn',
'jsdoc/no-multi-asterisks': 'warn',
'jsdoc/require-param-description': 'warn',
'jsdoc/require-param-name': 'warn',
@@ -104,8 +103,9 @@ module.exports = {
'jsdoc/require-yields-check': 'warn',
'jsdoc/valid-types': 'warn',
'jsdoc/require-jsdoc': ['warn', {
+ checkConstructors: false,
require: {
- ArrowFunctionExpression: true,
+ ArrowFunctionExpression: false,
ClassDeclaration: true,
ClassExpression: true,
FunctionDeclaration: true,
diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml
index 4ad2abd22..0c008061a 100644
--- a/.github/workflows/audit.yml
+++ b/.github/workflows/audit.yml
@@ -18,7 +18,7 @@ jobs:
audit:
strategy:
matrix:
- node-version: [ '20' ]
+ node-version: [ '22' ]
os: [ 'ubuntu-latest' ]
name: audit
runs-on: ${{ matrix.os }}
diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml
index df0fc6216..526211df2 100644
--- a/.github/workflows/build-docs.yml
+++ b/.github/workflows/build-docs.yml
@@ -18,7 +18,7 @@ jobs:
publish-docs:
strategy:
matrix:
- node-version: [ '20' ]
+ node-version: [ '22' ]
os: [ 'ubuntu-latest' ]
name: build-docs
runs-on: ${{ matrix.os }}
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 57f2b8b20..8a0b584a2 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -20,7 +20,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- node-version: [ 20, 22 ]
+ node-version: [ 20, 22, 24 ]
os: [ ubuntu-latest, windows-latest, macos-latest ]
install-command: [ i, ci ]
runs-on: ${{ matrix.os }}
diff --git a/.github/workflows/codeql-advanced.yml b/.github/workflows/codeql-advanced.yml
new file mode 100644
index 000000000..ec7ce58ff
--- /dev/null
+++ b/.github/workflows/codeql-advanced.yml
@@ -0,0 +1,100 @@
+# For most projects, this workflow file will not need changing; you simply need
+# to commit it to your repository.
+#
+# You may wish to alter this file to override the set of languages analyzed,
+# or to provide custom queries or build logic.
+#
+# ******** NOTE ********
+# We have attempted to detect the languages in your repository. Please check
+# the `language` matrix defined below to confirm you have the correct set of
+# supported CodeQL languages.
+#
+name: "CodeQL Advanced"
+
+on:
+ push:
+ branches: [ "master", "develop", "milestone*" ]
+ pull_request:
+ branches: [ "master", "develop", "milestone*" ]
+ schedule:
+ - cron: '37 18 * * 6'
+
+jobs:
+ analyze:
+ name: Analyze (${{ matrix.language }})
+ # Runner size impacts CodeQL analysis time. To learn more, please see:
+ # - https://gh.io/recommended-hardware-resources-for-running-codeql
+ # - https://gh.io/supported-runners-and-hardware-resources
+ # - https://gh.io/using-larger-runners (GitHub.com only)
+ # Consider using larger runners or machines with greater resources for possible analysis time improvements.
+ runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
+ permissions:
+ # required for all workflows
+ security-events: write
+
+ # required to fetch internal or private CodeQL packs
+ packages: read
+
+ # only required for workflows in private repositories
+ actions: read
+ contents: read
+
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - language: actions
+ build-mode: none
+ - language: javascript-typescript
+ build-mode: none
+ # CodeQL supports the following values keywords for 'language': 'actions', 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'rust', 'swift'
+ # Use `c-cpp` to analyze code written in C, C++ or both
+ # Use 'java-kotlin' to analyze code written in Java, Kotlin or both
+ # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
+ # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,
+ # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.
+ # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
+ # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+
+ # Add any setup steps before running the `github/codeql-action/init` action.
+ # This includes steps like installing compilers or runtimes (`actions/setup-node`
+ # or others). This is typically only required for manual builds.
+ # - name: Setup runtime (example)
+ # uses: actions/setup-example@v1
+
+ # Initializes the CodeQL tools for scanning.
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@v3
+ with:
+ languages: ${{ matrix.language }}
+ build-mode: ${{ matrix.build-mode }}
+ # If you wish to specify custom queries, you can do so here or in a config file.
+ # By default, queries listed here will override any specified in a config file.
+ # Prefix the list here with "+" to use these queries and those in the config file.
+
+ # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
+ # queries: security-extended,security-and-quality
+
+ # If the analyze step fails for one of the languages you are analyzing with
+ # "We were unable to automatically build your code", modify the matrix above
+ # to set the build mode to "manual" for that language. Then modify this step
+ # to build your code.
+ # βΉοΈ Command-line programs to run using the OS shell.
+ # π See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
+ - if: matrix.build-mode == 'manual'
+ shell: bash
+ run: |
+ echo 'If you are using a "manual" build mode for one or more of the' \
+ 'languages you are analyzing, replace this with the commands to build' \
+ 'your code, for example:'
+ echo ' make bootstrap'
+ echo ' make release'
+ exit 1
+
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@v3
+ with:
+ category: "/language:${{matrix.language}}"
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 792b2f30d..8d10020c2 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -18,7 +18,7 @@ jobs:
lint:
strategy:
matrix:
- node-version: [ '20' ]
+ node-version: [ '22' ]
os: [ 'ubuntu-latest' ]
name: lint
runs-on: ${{ matrix.os }}
diff --git a/.github/workflows/performance.yml b/.github/workflows/performance.yml
index 64a417635..f70b6b37d 100644
--- a/.github/workflows/performance.yml
+++ b/.github/workflows/performance.yml
@@ -14,7 +14,7 @@ jobs:
performance-test:
strategy:
matrix:
- node-version: [ '20' ]
+ node-version: [ '22' ]
os: [ 'ubuntu-latest' ]
name: Test performance
runs-on: ${{ matrix.os }}
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index e884f7ae8..acc67e571 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -1,6 +1,6 @@
name: Publish
permissions:
- contents: read
+ contents: write
pages: write
on:
@@ -12,7 +12,7 @@ jobs:
publish-docs:
strategy:
matrix:
- node-version: [ '20' ]
+ node-version: [ '22' ]
os: [ 'ubuntu-latest' ]
name: publish-docs
runs-on: ${{ matrix.os }}
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 1853ec7c7..51a87c303 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -18,7 +18,7 @@ jobs:
unit-tests:
strategy:
matrix:
- node-version: [ '20' ]
+ node-version: [ '22' ]
os: [ 'ubuntu-latest' ]
name: unit-tests
runs-on: ${{ matrix.os }}
@@ -37,7 +37,7 @@ jobs:
- name: Run tests
run: |
npm run test:unit.ci -- --coverage
-
+
- name: Upload coverage to Codecov
uses: codecov/codecov-action@6004246f47ab62d32be025ce173b241cd84ac58e # https://github.com/codecov/codecov-action/releases/tag/v1.0.13
env:
@@ -46,7 +46,7 @@ jobs:
browser-tests:
strategy:
matrix:
- node-version: [ '20' ]
+ node-version: [ '22' ]
os: [ 'ubuntu-latest' ]
name: browser-tests
runs-on: ${{ matrix.os }}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b47432ccd..1d5eb450d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,17 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
## [Unreleased]
+## [3.1.0] - 2025-10-14
+
+### Changed
+
+- Renamed the `arraySizeMethod` parameter in the `FunctionMetadata` interface to `sizeOfResultArrayMethod`. The `arraySizeMethod` is deprecated and will be removed in one of the next major releases. [#1401](https://github.com/handsontable/hyperformula/issues/1401)
+- Renamed the `arrayFunction` parameter in the `FunctionMetadata` interface to `enableArrayArithmeticForArguments`. The `arrayFunction` is deprecated and will be removed in one of the next major releases. [#1401](https://github.com/handsontable/hyperformula/issues/1401)
+
+### Fixed
+
+- Fixed an issue where the `OFFSET` function was ignoring the sheet reference in the provided address. [#1477](https://github.com/handsontable/hyperformula/issues/1477)
+
## [3.0.1] - 2025-08-11
### Fixed
diff --git a/DEV_DOCS.md b/DEV_DOCS.md
new file mode 100644
index 000000000..0197a804c
--- /dev/null
+++ b/DEV_DOCS.md
@@ -0,0 +1,9 @@
+# Dev Docs
+
+Random notes and things to know useful for maintainers and contributors.
+
+## Sources of the function translations
+
+HF supports internationalization and provides the localized function names for all built-in languages. When looking for the valid translations for the new functions, try these sources:
+- https://support.microsoft.com/en-us/office/excel-functions-translator-f262d0c0-991c-485b-89b6-32cc8d326889
+- http://dolf.trieschnigg.nl/excel/index.php
diff --git a/README.md b/README.md
index 6fe85f9cc..f82fba5e9 100644
--- a/README.md
+++ b/README.md
@@ -98,7 +98,7 @@ hf.setCellContents({ sheet: sheetId, row: 0, col: 0 }, [['Monthly Payment', '=PM
console.log(`${hf.getCellValue({ sheet: sheetId, row: 0, col: 0 })}: ${hf.getCellValue({ sheet: sheetId, row: 0, col: 1 })}`);
```
-[Run this code in StackBlitz](https://stackblitz.com/github/handsontable/hyperformula-demos/tree/3.0.x/mortgage-calculator)
+[Run this code in StackBlitz](https://stackblitz.com/github/handsontable/hyperformula-demos/tree/3.1.x/mortgage-calculator)
## Contributing
diff --git a/docs/guide/basic-operations.md b/docs/guide/basic-operations.md
index 591308df1..0bcc0a771 100644
--- a/docs/guide/basic-operations.md
+++ b/docs/guide/basic-operations.md
@@ -15,16 +15,16 @@ absolute, in all sheets affected by the change.
Operations affecting only the dependency graph should not decrease
performance. However, multiple operations that have an impact on
-calculation results may affect performance; these are `clearSheet`,
-`setSheetContent`, `setCellContents`, `addNamedExpression`,
-`changeNamedExpression`, and `removeNamedExpression`. It is advised
+calculation results may affect performance; these are [`clearSheet`](../api/classes/hyperformula.md#clearsheet),
+[`setSheetContent`](../api/classes/hyperformula.md#setsheetcontent), [`setCellContents`](../api/classes/hyperformula.md#setcellcontents), [`addNamedExpression`](../api/classes/hyperformula.md#addnamedexpression),
+[`changeNamedExpression`](../api/classes/hyperformula.md#changenamedexpression), and [`removeNamedExpression`](../api/classes/hyperformula.md#removenamedexpression). It is advised
to [batch](batch-operations.md) them.
## Sheets
### Adding a sheet
-A sheet can be added by using the `addSheet` method. You can pass a
+A sheet can be added by using the [`addSheet`](../api/classes/hyperformula.md#addsheet) method. You can pass a
name for it or leave it without a parameter. In the latter case the
method will create an autogenerated name for it. That name can then
be returned for further use.
@@ -37,7 +37,7 @@ const myNewSheet = hfInstance.addSheet();
hfInstance.addSheet('SheetName');
```
-You can also count sheets by using the `countSheets` method. This
+You can also count sheets by using the [`countSheets`](../api/classes/hyperformula.md#countsheets) method. This
method does not require any parameters.
```javascript
@@ -47,7 +47,7 @@ const sheetsCount = hfInstance.countSheets();
### Removing a sheet
-A sheet can be removed by using the `removeSheet` method. To do that
+A sheet can be removed by using the [`removeSheet`](../api/classes/hyperformula.md#removesheet) method. To do that
you need to pass a mandatory parameter: the ID of a sheet to be
removed.
This method returns [an array of changed cells](#changes-array).
@@ -59,13 +59,13 @@ const changes = hfInstance.removeSheet(0);
### Renaming a sheet
-A sheet can be renamed by using the `renameSheet` method. You need to
+A sheet can be renamed by using the [`renameSheet`](../api/classes/hyperformula.md#renamesheet) method. You need to
pass the ID of a sheet you want to rename (you can get it with the
-`getSheetId` method only if you know its name) along with a new name
+[`getSheetId`](../api/classes/hyperformula.md#getsheetid) method only if you know its name) along with a new name
as the first and second parameters, respectively.
```javascript
-// rename the first sheet
+// rename the first sheet
hfInstance.renameSheet(0, 'NewSheetName');
// you can retrieve the sheet ID if you know its name
@@ -77,7 +77,7 @@ hfInstance.renameSheet(sheetID, 'AnotherNewName');
### Clearing a sheet
-A sheet's content can be cleared with the `clearSheet` method. You need
+A sheet's content can be cleared with the [`clearSheet`](../api/classes/hyperformula.md#clearsheet) method. You need
to provide the ID of a sheet whose content you want to clear.
This method returns [an array of changed cells](#changes-array).
@@ -89,7 +89,7 @@ const changes = hfInstance.clearSheet(0);
### Replacing sheet content
Instead of removing and adding the content of a sheet you can replace
-it right away. To do so use `setSheetContent`, in which you can pass
+it right away. To do so use [`setSheetContent`](../api/classes/hyperformula.md#setsheetcontent), in which you can pass
the sheet ID and its new values.
This method returns [an array of changed cells](#changes-array).
@@ -102,7 +102,7 @@ const changes = hfInstance.setSheetContent(0, [['50'], ['60']]);
### Adding rows
-You can add one or more rows by using the `addRows` method. The first
+You can add one or more rows by using the [`addRows`](../api/classes/hyperformula.md#addrows) method. The first
parameter you need to pass is a sheet ID, and the second parameter
represents the position and the size of a block of rows to be added.
This method returns [an array of changed cells](#changes-array).
@@ -115,7 +115,7 @@ const changes = hfInstance.addRows(0, [0, 2]);
### Removing rows
-You can remove one or more rows by using the `removeRows` method. The
+You can remove one or more rows by using the [`removeRows`](../api/classes/hyperformula.md#removerows) method. The
first parameter you need to pass is a sheet ID, and the second
parameter represents the position and the size of a block of rows to
be removed.
@@ -129,13 +129,13 @@ const changes = hfInstance.removeRows(0, [0, 2]);
### Moving rows
-You can move one or more rows by using the `moveRows` method. You need
+You can move one or more rows by using the [`moveRows`](../api/classes/hyperformula.md#moverows) method. You need
to pass the following parameters:
* Sheet ID
* Starting row
* Number of rows to be moved
-* Target row
+* [Target row](../api/classes/hyperformula.md#moverows)
This method returns [an array of changed cells](#changes-array).
@@ -147,9 +147,9 @@ const changes = hfInstance.moveRows(0, 0, 1, 2);
### Reordering rows
-You can change the order of rows by using the `setRowOrder` method. You need to pass the following parameters:
+You can change the order of rows by using the [`setRowOrder`](../api/classes/hyperformula.md#setroworder) method. You need to pass the following parameters:
* Sheet ID
-* New row order
+* [New row order](../api/classes/hyperformula.md#setroworder)
This method returns [an array of changed cells](#changes-array).
@@ -162,7 +162,7 @@ const changes = hfInstance.setRowOrder(0, [2, 1, 0]);
### Adding columns
-You can add one or more columns by using the `addColumns` method.
+You can add one or more columns by using the [`addColumns`](../api/classes/hyperformula.md#addcolumns) method.
The first parameter you need to pass is a sheet ID, and the second
parameter represents the position and the size of a block of columns
to be added.
@@ -176,7 +176,7 @@ const changes = hfInstance.addColumns(0, [0, 2]);
### Removing columns
-You can remove one or more columns by using the `removeColumns` method.
+You can remove one or more columns by using the [`removeColumns`](../api/classes/hyperformula.md#removecolumns) method.
The first parameter you need to pass is a sheet ID, and the second
parameter represents the position and the size of a block of columns
to be removed.
@@ -190,27 +190,27 @@ const changes = hfInstance.removeColumns(0, [0, 2]);
### Moving columns
-You can move one or more columns by using the `moveColumns` method.
+You can move one or more columns by using the [`moveColumns`](../api/classes/hyperformula.md#movecolumns) method.
You need to pass the following parameters:
* Sheet ID
* Starting column
* Number of columns to be moved
-* Target column
+* [Target column](../api/classes/hyperformula.md#movecolumns)
This method returns [an array of changed cells](#changes-array).
```javascript
// track the changes triggered by moving
-// the first column in the first sheet into column 2
+// the first column in the first sheet into column 2
const changes = hfInstance.moveColumns(0, 0, 1, 2);
```
### Reordering columns
-You can change the order of columns by using the `setColumnOrder` method. You need to pass the following parameters:
+You can change the order of columns by using the [`setColumnOrder`](../api/classes/hyperformula.md#setcolumnorder) method. You need to pass the following parameters:
* Sheet ID
-* New column order
+* [New column order](../api/classes/hyperformula.md#setcolumnorder)
This method returns [an array of changed cells](#changes-array).
@@ -222,19 +222,19 @@ const changes = hfInstance.setColumnOrder(0, [2, 1, 0]);
## Cells
::: tip
-By default, cells are identified using a `SimpleCellAddress` which
+By default, cells are identified using a [`SimpleCellAddress`](../api/interfaces/simplecelladdress) which
consists of a sheet ID, column ID, and row ID, like this:
`{ sheet: 0, col: 0, row: 0 }`
Alternatively, you can work with the **A1 notation** known from
spreadsheets like Excel or Google Sheets. The API provides the helper
-function `simpleCellAddressFromString` which you can use to retrieve
-the `SimpleCellAddress` .
+function [`simpleCellAddressFromString`](../api/globals.md#simplecelladdressfromstring) which you can use to retrieve
+the [`SimpleCellAddress`](../api/interfaces/simplecelladdress) .
:::
### Moving cells
-You can move one or more cells using the `moveCells` method. You need
+You can move one or more cells using the [`moveCells`](../api/classes/hyperformula.md#movecells) method. You need
to pass the following parameters:
* Source range ([SimpleCellRange](../api/interfaces/simplecellrange))
@@ -256,8 +256,8 @@ const changes = hfInstance.moveCells({ start: source, end: source }, destination
### Updating cells
You can set the content of a block of cells by using the
-`setCellContents` method. You need to pass the top left corner address
-of a block as a simple cell address, along with the content to be set.
+[`setCellContents`](../api/classes/hyperformula.md#setcellcontents) method. You need to pass the top left corner address
+of a block as a [`SimpleCellAddress`](../api/interfaces/simplecelladdress), along with the content to be set.
It can be content for either a single cell or a set of cells in an array.
This method returns [an array of changed cells](#changes-array).
@@ -269,8 +269,8 @@ const changes = hfInstance.setCellContents({ col: 3, row: 0, sheet: 0 }, [['=B1'
### Getting cell value
-You can get the value of a cell by using `getCellValue` . Remember to
-pass the coordinates as a `SimpleCellAddress` .
+You can get the value of a cell by using [`getCellValue`](../api/classes/hyperformula.md#getcellvalue) . Remember to
+pass the coordinates as a [`SimpleCellAddress`](../api/interfaces/simplecelladdress) .
```javascript
// get the value of the B1 cell
@@ -279,8 +279,8 @@ const B1Value = hfInstance.getCellValue({ sheet: 0, col: 1, row: 0 });
### Getting cell formula
-You can retrieve the formula from a cell by using `getCellFormula`.
-Remember to pass the coordinates as a `SimpleCellAddress` .
+You can retrieve the formula from a cell by using [`getCellFormula`](../api/classes/hyperformula.md#getcellformula).
+Remember to pass the coordinates as a [`SimpleCellAddress`](../api/interfaces/simplecelladdress) .
```javascript
// get the formula from the A1 cell
@@ -355,7 +355,7 @@ if (!isRemovable) {
## Changes array
-All data modification methods return an array of `ExportedChange`.
+All data modification methods return an array of [`ExportedChange`](../api/globals.md#exportedchange).
This is a collection of cells whose **values** were affected by an operation,
together with their absolute addresses and new values.
diff --git a/docs/guide/building.md b/docs/guide/building.md
index fd87ba93f..a781b05b8 100644
--- a/docs/guide/building.md
+++ b/docs/guide/building.md
@@ -38,7 +38,7 @@ format , builds ES6 version
* `npm run bundle:languages` - builds the languages
* `npm run bundle:typings` - generates TypeScript typing, only emits β.d.tsβ declaration files
-We use the Node 20 LTS in the build-chain and recommend this version for building. Note that for using (not building) HyperFormula, a wider range of Node versions is supported.
+We use the Node 22 LTS in the build-chain and recommend this version for building. Note that for using (not building) HyperFormula, a wider range of Node versions is supported.
## Verify the build
diff --git a/docs/guide/built-in-functions.md b/docs/guide/built-in-functions.md
index adb05c579..07d4075c6 100644
--- a/docs/guide/built-in-functions.md
+++ b/docs/guide/built-in-functions.md
@@ -64,8 +64,8 @@ Total number of functions: **{{ $page.functionsCount }}**
| Function ID | Description | Syntax |
|:-----------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:----------------------------------------------------|
| DATE | Returns the specified date as the number of full days since [`nullDate`](../api/interfaces/configparams.md#nulldate). | DATE(Year, Month, Day) |
-| DATEDIF | Calculates distance between two dates, in provided unit parameter. | DATEDIF(Date1, Date2, Units) |
-| DATEVALUE | Parses a date string and returns it as the number of full days since [`nullDate`](../api/interfaces/configparams.md#nulldate).
Accepts formats set by the [`dateFormats`](../api/interfaces/configparams.md#dateformats) option. | DATEVALUE(Datestring) |
+| DATEDIF | Calculates distance between two dates.
Supported units: "D" (days), "M" (months), "Y" (years), "MD" (days ignoring months and years), "YM" (months ignoring years), or "YD" (days ignoring years). | DATEDIF(Date1, Date2, Unit) |
+| DATEVALUE | Parses a date string and returns it as the number of full days since [`nullDate`](../api/interfaces/configparams.md#nulldate).
Accepts formats set by the [`dateFormats`](../api/interfaces/configparams.md#dateformats) option. | DATEVALUE(Datestring) |
| DAY | Returns the day of the given date value. | DAY(Number) |
| DAYS | Calculates the difference between two date values. | DAYS(Date2, Date1) |
| DAYS360 | Calculates the difference between two date values in days, in 360-day basis. | DAYS360(Date2, Date1[, Format]) |
@@ -81,7 +81,7 @@ Total number of functions: **{{ $page.functionsCount }}**
| NOW | Returns current date + time as a number of days since [`nullDate`](../api/interfaces/configparams.md#nulldate). | NOW() |
| SECOND | Returns second component of given time. | SECOND(Time) |
| TIME | Returns the number that represents a given time as a fraction of full day. | TIME(Hour, Minute, Second) |
-| TIMEVALUE | Parses a time string and returns a number that represents it as a fraction of a full day.
Accepts formats set by the [`timeFormats`](../api/interfaces/configparams.md#timeformats) option. | TIMEVALUE(Timestring) |
+| TIMEVALUE | Parses a time string and returns a number that represents it as a fraction of a full day.
Accepts formats set by the [`timeFormats`](../api/interfaces/configparams.md#timeformats) option. | TIMEVALUE(Timestring) |
| TODAY | Returns an integer representing the current date as the number of full days since [`nullDate`](../api/interfaces/configparams.md#nulldate). | TODAY() |
| WEEKDAY | Computes a number between 1-7 representing the day of week. | WEEKDAY(Date, Type) |
| WEEKNUM | Returns a week number that corresponds to the week of year. | WEEKNUM(Date, Type) |
@@ -499,7 +499,7 @@ Total number of functions: **{{ $page.functionsCount }}**
| SPLIT | Divides the provided text using the space character as a separator and returns the substring at the zero-based position specified by the second argument.
`SPLIT("Lorem ipsum", 0) -> "Lorem"`
`SPLIT("Lorem ipsum", 1) -> "ipsum"` | SPLIT(Text, Index) |
| SUBSTITUTE | Returns string where occurrences of Old_text are replaced by New_text. Replaces only specific occurrence if last parameter is provided. | SUBSTITUTE(Text, Old_text, New_text, [Occurrence]) |
| T | Returns text if given value is text, empty string otherwise. | T(Value) |
-| TEXT | Converts a number into text according to a given format.
By default, accepts the same formats that can be passed to the [`dateFormats`](../api/interfaces/configparams.md#dateformats) option, but can be further customized with the [`stringifyDateTime`](../api/interfaces/configparams.md#stringifydatetime) option. | TEXT(Number, Format) |
+| TEXT | Converts a number into text according to a given format.
By default, accepts the same formats that can be passed to the [`dateFormats`](../api/interfaces/configparams.md#dateformats) option, but can be further customized with the [`stringifyDateTime`](../api/interfaces/configparams.md#stringifydatetime) option. | TEXT(Number, Format) |
| TRIM | Strips extra spaces from text. | TRIM("Text") |
| UNICHAR | Returns the character created by using provided code point. | UNICHAR(Number) |
| UNICODE | Returns the Unicode code point of a first character of a text. | UNICODE(Text) |
diff --git a/docs/guide/compatibility-with-google-sheets.md b/docs/guide/compatibility-with-google-sheets.md
index 1d2497063..5e98ea3b4 100644
--- a/docs/guide/compatibility-with-google-sheets.md
+++ b/docs/guide/compatibility-with-google-sheets.md
@@ -15,6 +15,17 @@ Still, with the right configuration, you can achieve nearly full compatibility.
## Configure compatibility with Google Sheets
+### `TRUE` and `FALSE` constants
+
+Google Sheets has built-in constants (keywords) for the boolean values (`TRUE` and `FALSE`).
+
+To set up HyperFormula in the same way, define `TRUE` and `FALSE` as [named expressions](named-expressions.md), by using HyperFormula's [`TRUE()`](built-in-functions.md#logical) and [`FALSE()`](built-in-functions.md#logical) functions.
+
+```js
+hfInstance.addNamedExpression('TRUE', '=TRUE()');
+hfInstance.addNamedExpression('FALSE', '=FALSE()');
+```
+
### Array arithmetic mode
In Google Sheets, the [array arithmetic mode](arrays.md#array-arithmetic-mode) is disabled by default.
@@ -97,4 +108,11 @@ const options = {
leapYear1900: false, // set by default
smartRounding: true, // set by default
};
+
+// call the static method to build a new instance
+const hfInstance = HyperFormula.buildEmpty(options);
+
+// define TRUE and FALSE constants
+hfInstance.addNamedExpression('TRUE', '=TRUE()');
+hfInstance.addNamedExpression('FALSE', '=FALSE()');
```
diff --git a/docs/guide/compatibility-with-microsoft-excel.md b/docs/guide/compatibility-with-microsoft-excel.md
index 65f252f4e..c26d9efe5 100644
--- a/docs/guide/compatibility-with-microsoft-excel.md
+++ b/docs/guide/compatibility-with-microsoft-excel.md
@@ -56,7 +56,7 @@ Related options:
Microsoft Excel has built-in constants (keywords) for the boolean values (`TRUE` and `FALSE`).
-To set up HyperFormula in the same way, define `TRUE` and `FALSE` as [named expressions](named-expressions.md), by using HyperFormula's [`TRUE`](built-in-functions.md#logical) and [`FALSE`](built-in-functions.md#logical) functions.
+To set up HyperFormula in the same way, define `TRUE` and `FALSE` as [named expressions](named-expressions.md), by using HyperFormula's [`TRUE()`](built-in-functions.md#logical) and [`FALSE()`](built-in-functions.md#logical) functions.
```js
hfInstance.addNamedExpression('TRUE', '=TRUE()');
diff --git a/docs/guide/custom-functions.md b/docs/guide/custom-functions.md
index 3444cdacd..c19f3494e 100644
--- a/docs/guide/custom-functions.md
+++ b/docs/guide/custom-functions.md
@@ -258,12 +258,12 @@ export class MyCustomPlugin extends FunctionPlugin {
A function that returns an array will cause the `VALUE!` error unless you also
declare a companion method for the array size. To do that, provide the
-`arraySizeMethod` that calculates the size of the result array based on the
+`sizeOfResultArrayMethod` that calculates the size of the result array based on the
function arguments and returns an instance of the
[`ArraySize` class](../api/classes/arraysize.md).
::: tip
-When you use your custom function in a formula, `arraySizeMethod` is triggered every time the formula changes, but not when the dependencies of the formula change.
+When you use your custom function in a formula, `sizeOfResultArrayMethod` is triggered every time the formula changes, but not when the dependencies of the formula change.
This can cause unexpected behavior if the size of the result array depends on the values in the referenced cells.
:::
@@ -286,7 +286,7 @@ export class MyCustomPlugin extends FunctionPlugin {
MyCustomPlugin.implementedFunctions = {
DOUBLE_RANGE: {
method: 'doubleRange',
- arraySizeMethod: 'doubleRangeResultArraySize',
+ sizeOfResultArrayMethod: 'doubleRangeResultArraySize',
parameters: [{ argumentType: FunctionArgumentType.RANGE }],
},
};
@@ -363,7 +363,7 @@ This demo contains the implementation of both the
[`DOUBLE_RANGE`](#advanced-custom-function-example) custom functions.
Possible values: `NUMBER_RAW, NUMBER_DATE, NUMBER_TIME, NUMBER_DATETIME, NUMBER_CURRENCY, NUMBER_PERCENT`.
Default: `NUMBER_RAW` |
| `repeatLastArgs` | Number | For functions with a variable number of arguments: sets how many last arguments can be repeated indefinitely.
Default: `0` |
| `expandRanges` | Boolean | `true`: ranges in the function's arguments are inlined to (possibly multiple) scalar arguments.
Default: `false` |
| `isVolatile` | Boolean | `true`: the function is [volatile](volatile-functions.md).
Default: `false` |
| `isDependentOnSheetStructureChange` | Boolean | `true`: the function gets recalculated with each sheet shape change (e.g., when adding/removing rows or columns).
Default: `false` |
| `doesNotNeedArgumentsToBeComputed` | Boolean | `true`: the function treats reference or range arguments as arguments that don't create dependency (other arguments are properly evaluated).
Default: `false` |
-| `arrayFunction` | Boolean | `true`: the function enables the [array arithmetic mode](arrays.md) in its arguments and nested expressions.
Default: `false` |
+| `enableArrayArithmeticForArguments` | Boolean | `true`: the function enables the [array arithmetic mode](arrays.md) in its arguments and nested expressions.
Default: `false` |
| `vectorizationForbidden` | Boolean | `true`: the function will never get [vectorized](arrays.md#passing-arrays-to-scalar-functions-vectorization).
Default: `false` |
+| `arraySizeMethod` | String | Deprecated; Use `sizeOfResultArrayMethod` instead. |
+| `arrayFunction` | Boolean | Deprecated; Use `enableArrayArithmeticForArguments` instead. |
You can set the options in the static `implementedFunctions` property of your
function plugin:
@@ -400,14 +402,14 @@ MyCustomPlugin.implementedFunctions = {
// your argument validation options
},
],
- arraySizeMethod: 'myArraySizeMethod',
+ sizeOfResultArrayMethod: 'myArraySizeMethod',
returnNumberType: 'NUMBER_RAW',
repeatLastArgs: 0,
expandRanges: false,
isVolatile: false,
isDependentOnSheetStructureChange: false,
doesNotNeedArgumentsToBeComputed: false,
- arrayFunction: false,
+ enableArrayArithmeticForArguments: false,
vectorizationForbidden: false,
},
};
diff --git a/docs/guide/date-and-time-handling.md b/docs/guide/date-and-time-handling.md
index 98ad1fb0c..752d50170 100644
--- a/docs/guide/date-and-time-handling.md
+++ b/docs/guide/date-and-time-handling.md
@@ -5,6 +5,8 @@ The formats for the default date and time parsing functions can be set using con
- [`timeFormats`](../api/interfaces/configparams.md#timeformats),
- [`nullYear`](../api/interfaces/configparams.md#nullyear).
+The API reference of [`dateFormats`](../api/interfaces/configparams.md#dateformats) and [`timeFormats`](../api/interfaces/configparams.md#timeformats) describes the supported date and time formats in detail.
+
## Example
By default, HyperFormula uses the European date and time formats.
@@ -23,9 +25,7 @@ timeFormats: ['hh:mm', 'hh:mm:ss.sss'], // set by default
## Custom date and time handling
-HyperFormula offers the possibility to extend the number of supported
-date/time formats as well as the behavior of this functionality by exposing
-three options:
+If date and time formats supported by the [`dateFormats`](../api/interfaces/configparams.md#dateformats) and [`timeFormats`](../api/interfaces/configparams.md#timeformats) parameters are not enough, you can extend them by providing the following options:
- [`parseDateTime`](../api/interfaces/configparams.md#parsedatetime), which allows to provide a function that accepts
a string representing date/time and parses it into an actual date/time format
diff --git a/docs/guide/file-import.md b/docs/guide/file-import.md
index b7bf2a7b4..1c9d04d27 100644
--- a/docs/guide/file-import.md
+++ b/docs/guide/file-import.md
@@ -16,9 +16,9 @@ To import XLSX files, use a third-party [XLSX parser](https://www.npmjs.com/sear
### Example: Import XLSX files in Node
-This example uses [ExcelJS](https://www.npmjs.com/package/exceljs) to import XLSX files into HyperFormula.
+This example uses [ExcelJS](https://www.npmjs.com/package/exceljs) to import XLSX files into HyperFormula.
-See full example on [GitHub](https://github.com/handsontable/hyperformula-demos/tree/3.0.x/read-excel-file).
+See full example on [GitHub](https://github.com/handsontable/hyperformula-demos/tree/3.1.x/read-excel-file).
```js
const ExcelJS = require('exceljs');
@@ -43,18 +43,21 @@ function convertXlsxWorkbookToJavascriptArrays(workbook) {
const workbookData = {};
workbook.eachSheet((worksheet) => {
+ const sheetDimensions = worksheet.dimensions
const sheetData = [];
- worksheet.eachRow((row) => {
+ for (let rowNum = sheetDimensions.top; rowNum <= sheetDimensions.bottom; rowNum++) {
const rowData = [];
- row.eachCell((cell) => {
+ for (let colNum = sheetDimensions.left; colNum <= sheetDimensions.right; colNum++) {
+ const cell = worksheet.getCell(rowNum, colNum)
+
const cellData = cell.formula ? `=${cell.formula}` : cell.value;
rowData.push(cellData);
- });
+ }
sheetData.push(rowData);
- });
+ }
workbookData[worksheet.name] = sheetData;
})
diff --git a/docs/guide/integration-with-angular.md b/docs/guide/integration-with-angular.md
index 836977432..3c16cd97e 100644
--- a/docs/guide/integration-with-angular.md
+++ b/docs/guide/integration-with-angular.md
@@ -7,7 +7,7 @@ For more details, see the [client-side installation](client-side-installation.md
## Demo