Skip to content

TMP PR: Release/3.3.0#1671

Open
sequba wants to merge 21 commits into
masterfrom
release/3.3.0
Open

TMP PR: Release/3.3.0#1671
sequba wants to merge 21 commits into
masterfrom
release/3.3.0

Conversation

@sequba
Copy link
Copy Markdown
Contributor

@sequba sequba commented May 11, 2026

Note

Medium Risk
Mostly CI/docs/release-metadata changes, but it modifies GitHub Actions workflows (new cross-repo test/perf runs using secrets and coverage uploads) which can impact pipeline reliability and security if misconfigured.

Overview
Prepares the 3.3.0 release by updating CHANGELOG.md, docs release notes, and the documented list of built-in functions (including new Database category entries and new statistical/text functions).

Modernizes docs and guides: adds new integration pages (AI SDK, LangChain, MCP server), expands framework integration guides, switches embedded demos to StackBlitz links, and makes VuePress build output/base/hostname configurable via DOCS_* env vars (plus a new build.config.js).

Updates CI and tooling: reorders checkouts in existing workflows, adds a new PR-only performance benchmark workflow that compares base vs head and comments on the PR, enables coverage collection + Codecov upload, adds codecov.yml, ignores coverage/ and vendored test/hyperformula-tests/, bumps .nvmrc to Node 18, adds netlify.toml, and removes the legacy Makefile.

Reviewed by Cursor Bugbot for commit 3a286f6. Bugbot is set up for automated code reviews on this repo. Configure here.

sequba and others added 20 commits February 19, 2026 12:15
* Extend CI For private tests

* Extend CI For private tests

* Extend CI For private tests

* Extend CI For private tests

* Extend CI For private tests

* Extend CI For private tests

* Extend CI For private tests

* Extend CI For private tests

* Extend CI For private tests

* Extend CI For private tests

* Extend CI For private tests

* Extend CI For private tests

* Extend CI For private tests

* Extend CI For private tests

* Extend CI For private tests

* Add npm script test:fetch-private

* Adjust eslintingore

* Adjust test.yml GH workflow

* Add performance.yml GH workflow

* Setup codecov.yml

* Remove Makefile

* Bring back removed npm scripts

* Update test/README.md

* Add setup files for jest and karma

* Move codecov.yml to the repository root

* Fix typo in eslintignore file

---------

Co-authored-by: Kuba Sekowski <kuba.sekowski.dev@gmail.com>
### Context

The IRR function returns `#NUM!` error when the initial investment
significantly exceeds the sum of returns (e.g., `=IRR({-150000, 12000,
15000, 18000})`). Excel correctly returns ~-41% for this case.

**Root cause:** The `irrCore` Newton-Raphson solver overshoots past the
lower bound of -1 on the first iteration when the solution is a strongly
negative rate. The code then unconditionally returns `#NUM!`.

**Fix:** Replace the unconditional error with a bisection-based clamp.
When Newton-Raphson overshoots past -1, bisect between the current rate
and -1: `newRate = (rate - 1) / 2`. This is guaranteed to stay in the
valid domain (`> -1`) and converges linearly until close enough for
quadratic Newton convergence to take over.

### How did you test your changes?

Added 5 unit tests in the private tests repo covering:
- Bug reproduction: `[-150000, 12000, 15000, 18000]` with default guess
- Reversed cash flow signs: `[150000, -12000, -15000, -18000]`
- Highly negative IRR (near total loss): `[-10000, 100, 100, 100]`
- Negative IRR with explicit guess
- Large investment with many small returns

All 42 IRR tests pass (37 existing + 5 new), no regressions.

### Types of changes
- [x] Bug fix (a non-breaking change that fixes an issue)

### Related issues:
1. Fixes #1628

### Checklist:
- [x] I have reviewed the guidelines about [Contributing to
HyperFormula](https://hyperformula.handsontable.com/guide/contributing.html)
and I confirm that my code follows the code style of this project.
- [ ] I have signed the [Contributor License
Agreement](https://goo.gl/forms/yuutGuN0RjsikVpM2).
- [x] My change is compliant with the
[OpenDocument](https://docs.oasis-open.org/office/OpenDocument/v1.3/os/part4-formula/OpenDocument-v1.3-os-part4-formula.html)
standard.
- [x] My change is compatible with Microsoft Excel.
- [x] My change is compatible with Google Sheets.
- [ ] I described my changes in the
[CHANGELOG.md](https://github.com/handsontable/hyperformula/blob/master/CHANGELOG.md)
file.
- [ ] My changes require a documentation update.
- [ ] My changes require a migration guide.


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Small, localized numerical-solver change plus non-runtime
test/benchmark script updates; primary risk is altered IRR convergence
behavior on edge-case inputs.
> 
> **Overview**
> Fixes `IRR` returning `#NUM!` for strongly negative solutions by
clamping Newton-Raphson iterations in `irrCore` when the next step
overshoots past `-1` (bisects back into the valid domain instead of
immediately erroring).
> 
> Updates tooling/docs around the private test suite: renames the setup
script to `test:setup-private`, adjusts `fetch-tests.sh` to create a
missing branch from `develop` (and pull appropriately), and repoints
benchmark scripts to `test/hyperformula-tests/performance`. Also records
the IRR fix in `CHANGELOG.md`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
34b1265. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…alue for an optional parameter (#1631)

## Problem

When a user writes `=ADDRESS(1,1,)` or `=ADDRESS(1,1,1,)`, the empty
argument
is coerced to `0`/`false` instead of using the parameter's declared
`defaultValue`.

Excel 2021 and Google Sheets treat empty args as the zero-value for the
type
(`0`/`FALSE`) for **all functions except ADDRESS**, where empty `absNum`
and
`a1Style` use their declared defaults (1 and `true`).

Fixes #1632

## Fix

- Add `emptyAsDefault` opt-in flag to `FunctionArgument` interface
- In `coerceArgumentsToRequiredTypes`: when `rawArg === EmptyValue` AND
`emptyAsDefault` is set AND `defaultValue` is declared → substitute
`defaultValue`
- Apply `emptyAsDefault: true` only to ADDRESS `absNum` and `a1Style`
parameters

## Tests

Regression tests in `handsontable/hyperformula-tests` (branch
`fix/empty-default-value`):
- ADDRESS: isolated tests for empty `absNum`, empty `a1Style`, both
empty
- LOG, MATCH, VLOOKUP, HLOOKUP: confirm empty → zero-value (not
defaultValue)
- `optional-parameters.spec.ts`: confirms empty args use zero-value
coercion (not defaultValue) when `emptyAsDefault` is not set



<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Touches core `FunctionPlugin` argument evaluation/coercion to
distinguish syntactically empty arguments, which could subtly affect
coercion behavior across many functions if misapplied. Change is gated
behind an opt-in `emptyAsDefault` flag and only enabled for `ADDRESS`
parameters in this PR.
> 
> **Overview**
> Fixes `ADDRESS` so syntactically empty optional arguments (e.g.
`=ADDRESS(2,3,,FALSE())`) use the parameter `defaultValue` instead of
being coerced to the type’s zero-value.
> 
> Adds an opt-in `emptyAsDefault` flag to `FunctionArgument` and extends
`FunctionPlugin`’s argument evaluation pipeline to track whether each
argument was syntactically empty, allowing coercion to substitute
`defaultValue` when `emptyAsDefault` is enabled. Documentation and
changelog are updated to reflect the new option and the `ADDRESS`
behavior fix.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
7c6fc7c. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adding `Definition of Done for the code changes` to the DEV_DOCS.md

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Documentation-only change that adds contribution/process guidance; no
runtime behavior or data/security impact.
> 
> **Overview**
> Adds a new **"Definition of Done"** section to `DEV_DOCS.md`
describing what production-code PRs must include before review (code
changes incl. i18n packs when relevant, tests expectations for internal
vs. external contributors, related docs/migration guide updates,
JSDoc/technical docs, changelog entry, and PR description).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
0d7351f. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## Summary

Adds the `TEXTJOIN` function — joins text from multiple strings and/or
ranges with a configurable delimiter.

Replaces #1625 (was opened from fork, now from upstream branch
directly).

### Features
- Scalar and array/range delimiter support with cycling behavior
- `ignore_empty` parameter to skip empty strings
- Type coercion (numbers, booleans → strings)
- Error propagation from both delimiter and text arguments
- 32,767 character limit (Excel compatibility)
- i18n translations for all 17 supported languages
- Documentation in `built-in-functions.md`

### Implementation
- New `textjoin` method + `flattenArgToStrings` helper in `TextPlugin`
- `repeatLastArgs: 1` metadata pattern (same as SUMPRODUCT, etc.)
- Defensive `CellError` check on `coerceScalarToString` return value

### Changed files
| File | Change |
|------|--------|
| `src/interpreter/plugin/TextPlugin.ts` | `textjoin()` +
`flattenArgToStrings()` |
| `src/error-message.ts` | `TextJoinResultTooLong` message |
| `src/i18n/languages/*.ts` (17 files) | TEXTJOIN translations |
| `docs/guide/built-in-functions.md` | TEXTJOIN row (alphabetically
between TEXT and TRIM) |

### Review feedback addressed (from #1625)
- Tests moved to private `hyperformula-tests` repo (companion PR
pending)
- Fixed docs alphabetical ordering
- Fixed unsafe `as string` cast in `flattenArgToStrings`

## Test plan

- [x] 35 tests in
`hyperformula-tests/unit/interpreter/function-textjoin.spec.ts`
- [x] Full suite: 480 suites / 5396 tests passed

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Adds a new interpreter function (`TEXTJOIN`) with range flattening and
type coercion, which touches formula evaluation paths and may introduce
edge-case regressions around error propagation and large-string
handling.
> 
> **Overview**
> Adds the new `TEXTJOIN` spreadsheet function, including interpreter
support for joining scalars and ranges with a delimiter (including
delimiter cycling), optional skipping of empty strings, and consistent
error propagation.
> 
> Introduces a new `ErrorMessage.ResultTooLong` and enforces Excel’s
32,767-character output limit (returning `#VALUE!` when exceeded).
> 
> Updates function documentation, the unreleased changelog, and adds
`TEXTJOIN` translations across all supported language packs.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
81426d7. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Kuba Sekowski <jakub.sekowski@handsontable.com>
Co-authored-by: Claude <noreply@anthropic.com>
…ndoRedo (#1638)

## Summary

Fixes #1629. Closes #1633. Closes #1634.

Two unbounded memory leaks in long-running HyperFormula instances:

- **`LTAS.transformations[]`** grew linearly with every structural
operation (addRows, removeRows, moveCells, etc.) and was never cleaned
up. Fixed by introducing **threshold-based compaction** with
`versionOffset` — once 50+ transformations accumulate, all consumers
(FormulaVertex, ColumnIndex) are force-updated, then the array is
released while the logical version remains monotonically increasing.

- **`UndoRedo.oldData`** grew linearly even when entries were evicted
from the undo stack. Fixed by tracking which LTAS versions each
`UndoEntry` references (`getReferencedOldDataVersions()`), cleaning up
on eviction/clear, guarding against writes when `undoLimit === 0`, and
running orphan cleanup after compaction to handle a race condition where
lazy-apply re-inserts already-evicted keys.

### Changed files

| File | Change |
|------|--------|
| `LazilyTransformingAstService.ts` | `versionOffset`, `compact()`,
`needsCompaction()` with threshold=50, offset-aware iteration |
| `UndoRedo.ts` | `getReferencedOldDataVersions()` on interface + 7
subclasses, eviction cleanup, `undoLimit===0` guard,
`cleanupOrphanedOldData()`, `forceApply` parity in
`undoMoveRows`/`undoMoveColumns` |
| `HyperFormula.ts` | Compaction trigger in
`recomputeIfDependencyGraphNeedsIt()` |
| `ColumnIndex.ts` | `forceApplyPostponedTransformations()` — iterates
all ValueIndex entries |
| `ColumnBinarySearch.ts` | No-op `forceApplyPostponedTransformations()`
|
| `SearchStrategy.ts` | New method on `ColumnSearchStrategy` interface |
| `Operations.ts` | Added `columnSearch.forceApply` to undo path (no
compact — centralized in HyperFormula.ts) |

### What is NOT fixed here

- **Parser cache** (`ParserWithCaching`) — unbounded growth tracked
separately in #1635

## Test plan

- 18 dedicated tests in `hyperformula-tests` — see companion PR in that
repo
- Full test suite: **480 suites / 5396 tests passed**
- Benchmark validated threshold=50 as optimal (eager compaction is ~18×
slower on a 2.5k formula sheet)

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Touches core recalculation/transform and undo/redo paths; while aimed
at memory safety, compaction/cleanup timing could affect formula
correctness or undo behavior in edge cases.
> 
> **Overview**
> Prevents unbounded memory growth in long-running engines by **adding
threshold-based compaction** of lazy formula transformations and by
**cleaning up undo snapshot (`oldData`) entries** when undo/redo stack
entries are cleared or evicted.
> 
> Introduces new config `maxPendingLazyTransformations` (default `50`)
and wires it into engine construction; when the threshold is reached,
`HyperFormula` forces pending transformations to be applied (dependency
graph + column search), compacts the transformation history, and prunes
orphaned `UndoRedo.oldData`. Column search strategies now expose
`forceApplyPostponedTransformations()` (real implementation for
`ColumnIndex`, no-op for binary search), and undo for move operations
ensures postponed transformations are applied before restoring old data.
Documentation and changelog are updated accordingly.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
d8ebe1d. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Kuba Sekowski <jakub.sekowski@handsontable.com>
## Problem

HyperFormula was missing the SEQUENCE dynamic array function for
generating sequential number arrays.

## Fix

Implements `SEQUENCE(rows, [cols], [start], [step])` as a new
`SequencePlugin`:

- Returns a rows×cols array of sequential numbers, filled row-major
- Parse-time array size prediction via `sequenceArraySize()` — handles
NUMBER and STRING literals; non-literal args (cell refs, formulas)
return `#VALUE!` (architectural limitation: array size must be known at
parse time)
- Error types match Excel: negative dims → `#VALUE!`, zero dims →
`#NUM!` (mapped from Excel's `#CALC!`)
- `emptyAsDefault: true` on optional params — empty args like
`=SEQUENCE(3,,,)` use declared defaults
- i18n for all 17 languages with proper Excel-localized names

## Changed files

| File | Change |
|------|--------|
| `src/interpreter/plugin/SequencePlugin.ts` | New plugin: `sequence()`
+ `sequenceArraySize()` |
| `src/interpreter/plugin/index.ts` | Plugin registration |
| `src/i18n/languages/*.ts` (17 files) | SEQUENCE translations |
| `docs/guide/built-in-functions.md` | SEQUENCE row in Array functions
table |
| `docs/guide/release-notes.md` | Unreleased section |
| `CHANGELOG.md` | Added entry |
| `test/smoke.spec.ts` | 3 smoke tests |
| `test/fetch-tests.sh` | Robustness fix for `git pull` |

## Tests

Regression tests in `handsontable/hyperformula-tests` (branch
`feature/SEQUENCE`):

| Group | Tests | Coverage |
|-------|-------|----------|
| Core sanity | #1#8 | Basic usage, MS docs examples |
| Default parameters | #9#13 | Omitted cols/start/step |
| Empty args | #14#21 | emptyAsDefault behavior |
| Step variants | #22#28 | Zero, negative, fractional step |
| Truncation | #29#35 | Fractional dims, trunc-to-zero |
| Error conditions | #36#48 | Zero/negative dims, text, arity,
propagation |
| Type coercion | #49#59 | Booleans, strings, cell refs, empty cells |
| Large sequences | #60#63 | 100×100, 1000×1, 1×1000 |
| Fill order | #64#69 | Row-major verification |
| Function combos | #70#74 | SUM, AVERAGE, MAX, MIN, COUNT |
| Behavioral | #75#80 | Max dims, spill |
| Dynamic args | #81#82 | Architectural limitation (cell ref → #VALUE!)
|

- 82/82 PASS confirmed in Excel desktop (Microsoft 365)
- 3 smoke tests in `test/smoke.spec.ts`



<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Adds a new array-producing built-in (`SEQUENCE`) with parse-time size
prediction rules; mistakes here can affect array vertex creation and
spill/error behavior across formulas. Remaining changes are
documentation/i18n updates plus a minor test script tweak.
> 
> **Overview**
> Adds the `SEQUENCE(rows, [cols], [start], [step])` built-in via a new
`SequencePlugin`, generating row-major numeric arrays and enforcing
dimension/max-sheet limits with appropriate errors.
> 
> Introduces parse-time result sizing (`sequenceArraySize`) that only
accepts literal `rows`/`cols` (non-literal dimensions now yield
`#VALUE!` due to unknown output size), and wires the plugin into the
interpreter exports.
> 
> Updates changelog and docs to list `SEQUENCE`, adds function name
translations across all language packs, and adjusts
`test/fetch-tests.sh` to pull explicitly from `origin` for the current
branch.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
b08cd79. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Claude <noreply@anthropic.com>
## Summary
- Add three new landing pages under Framework integration: HyperFormula
AI SDK, Integration with LangChain/LangGraph, and HyperFormula MCP
Server
- Rename sidebar "Overview" section to "About" and move it above
Miscellaneous (2nd to last)
- Promote "Getting started" to second position in sidebar (right after
Introduction)

## Test plan
- [ ] Run `npm run docs:dev` and verify sidebar order: Introduction →
Getting started → Framework integration → ... → About → Miscellaneous
- [ ] Verify new pages render at `/guide/ai-sdk`,
`/guide/integration-with-langchain`, `/guide/mcp-server`
- [ ] Verify existing Overview pages (Quality, Supported browsers, etc.)
still accessible at original URLs

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: documentation-only changes that add new guide pages and
reorder sidebar navigation without affecting runtime code.
> 
> **Overview**
> Adds three new guide pages describing AI-focused integrations:
`ai-sdk`, `integration-with-langchain`, and `mcp-server`.
> 
> Reorganizes the VuePress sidebar by renaming the prior *Overview*
section to **About**, moving it near the end, and renaming *Framework
integration* to **Integrations** while linking in the new AI docs pages.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
1688f23. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Kuba Sekowski <jakub.sekowski@handsontable.com>
### Context
<!--- Why are your changes required? What problem do they solve? -->

https://app.clickup.com/t/9015210959/HF-116

### How did you test your changes?
<!--- Describe in detail how you tested your changes. -->

unit tests

### Types of changes
<!--- What types of changes does your code introduce? Put an `x` in each
box that applies. -->
- [ ] Breaking change (a fix or a feature because of which an existing
functionality doesn't work as expected anymore)
- [x] New feature or improvement (a non-breaking change that adds
functionality)
- [ ] Bug fix (a non-breaking change that fixes an issue)
- [ ] Additional language file, or a change to an existing language file
(translations)
- [ ] Change to the documentation

### Checklist:
<!--- Go through the points below, and put an `x` in each box that
applies. -->
<!--- If you're unsure about any of these, contact us. We're always glad
to help! -->
- [ ] I have reviewed the guidelines about [Contributing to
HyperFormula](https://hyperformula.handsontable.com/guide/contributing.html)
and I confirm that my code follows the code style of this project.
- [ ] I have signed the [Contributor License
Agreement](https://goo.gl/forms/yuutGuN0RjsikVpM2).
- [ ] My change is compliant with the
[OpenDocument](https://docs.oasis-open.org/office/OpenDocument/v1.3/os/part4-formula/OpenDocument-v1.3-os-part4-formula.html)
standard.
- [ ] My change is compatible with Microsoft Excel.
- [ ] My change is compatible with Google Sheets.
- [ ] I described my changes in the
[CHANGELOG.md](https://github.com/handsontable/hyperformula/blob/master/CHANGELOG.md)
file.
- [ ] My changes require a documentation update.
- [ ] My changes require a migration guide.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **High Risk**
> Updates license validation logic, a compliance-critical area, by
adding a hardcoded key that will always be treated as valid; mistakes
here could unintentionally bypass licensing checks.
> 
> **Overview**
> Adds a new hardcoded trial license key
(`hftrial-0168e-1f2b7-47158-70b05-0842f`) to the whitelist in
`checkLicenseKeyValidity`, causing that exact value to be treated as
`valid` without schema/expiry checks.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
fd095ae. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## Summary

- Implement 6 new functions: PERCENTILE, PERCENTILE.INC, PERCENTILE.EXC,
QUARTILE, QUARTILE.INC, QUARTILE.EXC
- New `PercentilePlugin` with inclusive/exclusive interpolation helpers
- i18n translations for all 17 languages (verified against Excel
function translator)
- CHANGELOG entry and built-in-functions.md updated

## Changes

- `src/interpreter/plugin/PercentilePlugin.ts` — new plugin
- `src/interpreter/plugin/index.ts` — export registration
- `src/i18n/languages/*.ts` — all 17 languages
- `docs/guide/built-in-functions.md` — 6 new entries (alphabetical)
- `CHANGELOG.md` — added entry

## Test plan

- [ ] 57 unit tests in hyperformula-tests (function-percentile.spec.ts)
- [ ] Excel validation workbook (107 cases) — open in Excel 365 desktop,
verify all PASS
- [ ] `npm run lint` passes
- [ ] `npm run compile` passes
- [ ] CI green

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Introduces new statistical function implementations and aliases in the
interpreter; main risk is correctness/edge-case parity with spreadsheet
semantics and potential impacts to function translation tables.
> 
> **Overview**
> Adds `PERCENTILE`/`QUARTILE` function families, including `.INC` and
`.EXC` variants, via a new `PercentilePlugin` that computes
percentiles/quartiles with linear interpolation and appropriate `#NUM!`
error handling for out-of-range inputs.
> 
> Registers the plugin export, adds function aliases
(`PERCENTILE`→`PERCENTILE.INC`, `QUARTILE`→`QUARTILE.INC`), and updates
built-in function documentation, changelog, and all language packs to
include translations for the new function names.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
7172a52. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Kuba Sekowski <jakub.sekowski@handsontable.com>
## Summary
- Move hardcoded `base: '/'` and the implicit dist output path out of
`docs/.vuepress/config.js` so the docs site can be deployed under a
sub-path (e.g. `/docs/`) without editing the config file.
- Add `docs/.vuepress/build.config.js` as a single place to set
production values (`base: '/docs/'`, `dest: 'docs/.vuepress/dist/docs'`,
sitemap `hostname`).
- Resolution order for each setting: env var (`DOCS_BASE` / `DOCS_DEST`
/ `DOCS_HOSTNAME`) → `build.config.js` → existing built-in default.
`base` is normalized to start and end with `/`.
- No sitemap plugin change needed — `vuepress-plugin-sitemap` already
prepends `base` to every URL and writes `sitemap.xml` into the
configured `dest`.

## Test plan
- [ ] `npm run docs:build` completes successfully.
- [ ] Output is written to `docs/.vuepress/dist/docs/` (not
`docs/.vuepress/dist/`).
- [ ] `docs/.vuepress/dist/docs/index.html` references assets under
`/docs/...`.
- [ ] `docs/.vuepress/dist/docs/sitemap.xml` exists and every `<loc>` is
`https://hyperformula.handsontable.com/docs/...`.
- [ ] Overriding via env still works: `DOCS_BASE=/
DOCS_DEST=docs/.vuepress/dist npm run docs:build` reproduces the old
layout.
- [ ] `npm run docs:dev` still serves locally.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Medium risk because it changes docs build/deploy configuration (base
path, output directory, sitemap hostname) and upgrades the expected Node
version to 18, which could affect CI/hosting builds if environments
aren’t aligned.
> 
> **Overview**
> Makes the VuePress docs build configurable by introducing
`docs/.vuepress/build.config.js` and allowing `DOCS_BASE`, `DOCS_DEST`,
and `DOCS_HOSTNAME` to override `base`, build output `dest`, and sitemap
`hostname` (with `base` normalized to include leading/trailing `/`).
> 
> Updates deployment defaults to publish docs under `/docs/` and output
to `docs/.vuepress/dist/docs`, and adds `netlify.toml` plus a `.nvmrc`
bump to Node 18 to align the build environment.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
67f6148. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## Summary
Follow-up to #1663. The Netlify deploy succeeded but
`https://hyperformula-docs.netlify.app/docs/` returns 404.

Root cause: with `base: '/docs/'`, VuePress emits assets and internal
links under `/docs/...` and writes the build to
`docs/.vuepress/dist/docs/`. Setting `publish =
"docs/.vuepress/dist/docs"` made Netlify serve those files at `/`, so
the page rendered but every internal `/docs/...` reference 404'd. The
publish dir must be the **parent** of the base path so the on-disk
`docs/` subdirectory becomes the URL `/docs/`.

Change: `publish = "docs/.vuepress/dist"` in `netlify.toml`.

## Test plan
- [ ] Netlify deploys successfully.
- [ ] `https://hyperformula-docs.netlify.app/docs/` renders the docs
home (no 404).
- [ ] Sub-pages like `/docs/guide/demo.html` load with assets and CSS
intact.
- [ ] `/sitemap.xml` is reachable and entries point at
`https://hyperformula.handsontable.com/docs/...`.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk configuration-only change that affects where Netlify serves
built docs from; primary risk is misconfiguration leading to broken/404
docs paths.
> 
> **Overview**
> Fixes the Netlify deployment config by changing the `publish`
directory from `docs/.vuepress/dist/docs` to `docs/.vuepress/dist`,
ensuring the built `docs/` subdirectory is served at `/docs/` and
internal asset/link paths resolve correctly.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
be5594b. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
### Context

Implements all 12 Excel database functions (D-functions family).
Originally scoped to DCOUNT only, expanded to the full family since all
share the same infrastructure (field resolution, criteria parsing, row
matching).

### How did you test your changes?

- 185 unit tests in hyperformula-tests
(handsontable/hyperformula-tests#9)
- 167-case Excel validation workbook (all PASS in Excel Desktop)
- 147-test runtime integration suite + 30 edge case tests (booleans,
negatives, zeros, wildcards, large DB, comparison operators)
- Verified all error types match Excel precisely (#VALUE!, #DIV/0!,
#NUM!)

### Types of changes

- [x] New feature or improvement (a non-breaking change that adds
functionality)
- [x] Additional language file, or a change to an existing language file
(translations)
- [x] Change to the documentation

### Related issues:
1. Fixes HF-85

### Checklist:

- [x] I have reviewed the guidelines about Contributing to HyperFormula
and I confirm that my code follows the code style of this project.
- [x] My change is compatible with Microsoft Excel.
- [x] My change is compatible with Google Sheets.
- [x] I described my changes in the CHANGELOG.md file.
- [x] My changes require a documentation update.

---

## Summary

- 12 database functions: DCOUNT, DCOUNTA, DSUM, DAVERAGE, DMAX, DMIN,
DGET, DPRODUCT, DSTDEV, DSTDEVP, DVAR, DVARP
- New `DatabasePlugin` (533 lines) with shared infrastructure
- i18n translations for all 17 languages (proper Excel-localized names)
- Documentation: `built-in-functions.md` (Database section),
`known-limitations.md` (Nuances)

## Implementation

- `withDatabaseArgs()` helper eliminates boilerplate across all 12
functions
- `resolveFieldIndex()` — string (case-insensitive header match) or
1-based numeric index with `Math.trunc()`
- `buildDatabaseCriteria()` — OR across rows, AND within row, reuses
`CriterionBuilder`
- `rowMatchesCriteria()` — `.some()` (OR) + `.every()` (AND)
- `collectNumericValues()` — shared by DSTDEV/DSTDEVP/DVAR/DVARP

## Excel behavior edge cases

| Function | Edge case | Behavior |
|---|---|---|
| DMAX, DMIN, DPRODUCT | No matches | Returns 0 |
| DGET | 0 matches / 2+ matches | #VALUE! / #NUM! |
| DAVERAGE | No numeric values | #DIV/0! |
| DSTDEV, DVAR | ≤1 value | #DIV/0! (sample, n-1) |
| DSTDEVP, DVARP | 1 value / 0 values | 0 / #DIV/0! (population, n) |

## Linked

- Tests PR: handsontable/hyperformula-tests#9
- ClickUp: HF-85

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Adds new interpreter functionality that affects formula evaluation
semantics (criteria parsing, error handling, and aggregation behavior),
though changes are largely additive and isolated to a new plugin plus
docs/i18n updates.
> 
> **Overview**
> Adds a new `DatabasePlugin` implementing the 12 Excel database
functions (`DCOUNT`, `DCOUNTA`, `DSUM`, `DAVERAGE`, `DMAX`, `DMIN`,
`DGET`, `DPRODUCT`, `DSTDEV`, `DSTDEVP`, `DVAR`, `DVARP`), including
shared logic for field resolution, criteria parsing, row matching, and
Excel-like error propagation.
> 
> Updates the public surface by exporting the plugin, adding
translations for these functions across language packs, and expanding
docs/CHANGELOG to include a new **Database** functions category and
function list.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
74c4397. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…1653)

## Summary

Expand the four framework integration pages (React, Angular, Vue,
Svelte) from one-line redirects into self-contained guides with code
snippets extracted from the respective Stackblitz demos.

Each guide's primary snippet is a simplified version of the demo's
framework pattern — same lifecycle hooks, same service architecture,
same reactivity approach — with simplified data (`buildFromArray`
instead of Employee Table).

## Design rationale

### Snippets from demos, not invented patterns

Per review feedback: every code snippet must match what's in the
corresponding Stackblitz demo. This ensures the snippets are tested,
idiomatic, and consistent with what users see when they click the demo
link. Patterns not present in demos (e.g., Angular Signals, Svelte 5
runes) are deliberately excluded until validated by a framework expert.

| Framework | Demo file | Primary pattern in guide |
|---|---|---|
| React | `react-demo/src/lib/employee/employee.provider.tsx` | `useRef`
+ `useEffect` init/cleanup + `useState` |
| Angular | `angular-demo/src/app/employees/employees.service.ts` |
`@Injectable` + `BehaviorSubject` + `async` pipe |
| Vue | `vue-3-demo/src/lib/employees-data-provider.ts` | Class wrapper
with private HF field + `ref` |
| Svelte | `svelte-demo/src/routes/Hyperformula.svelte` |
`buildFromArray` + `getCellValue` + `on:click` + `onDestroy` |

### Other decisions

- **TypeScript** in all snippets (HF ships `.d.ts` typings)
- **`licenseKey: 'gpl-v3'`** in every snippet (without it, engine throws
license warning)
- **SSR notes** for Next.js, Nuxt, SvelteKit (HF is SSR-safe — no
browser-only API dependency — but instantiating it server-side is wasted
work, so each framework's SSR section defers to client lifecycle)
- **VuePress template fix** — Stackblitz links use `<a :href>` Vue
binding instead of `{{ }}` interpolation in markdown

## Test plan

- [x] Render docs locally / verify all four integration pages — all 4
pages return HTTP 200 on the Netlify deploy preview for the latest
commit (proxies `npm run docs:dev`)
- [x] Click each Stackblitz demo link — all 5 URLs (4 frameworks +
custom-functions) reachable, each
`hyperformula-demos@3.2.x/<framework>-demo` subdir exists
- [x] Verify primary snippets match demo patterns — React:
`useRef`/`useEffect`/`useState`; Angular:
`@Injectable`/`BehaviorSubject`/`async` pipe; Vue: class wrapper + `ref`
(the `markRaw` pattern is documented in Troubleshooting, not the primary
snippet); Svelte: `buildFromArray`/`getCellValue`/`on:click`/`onDestroy`
- [x] Verify no untested patterns remain — no Signals, no
`$state`/`$derived` runes, no NgZone; Pinia is mentioned only in a Vue
Troubleshooting note that warns against putting the engine into Pinia
state, not as a recommended pattern
- [x] Confirm `licenseKey: 'gpl-v3'` present in every snippet —
react/angular: 1× (main snippet); vue: 2× (main + Troubleshooting
markRaw demo); svelte: 2× (basic + SSR variants)
- [x] Confirm `destroy()` cleanup present in every applicable component
snippet — react/angular: 1× (main snippet); vue: 1× (main snippet —
Troubleshooting markRaw demo is illustrative, not a full component);
svelte: 2× (basic + SSR variants)

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk documentation-only change that adds new framework-specific
guidance and code snippets; no runtime/library behavior is modified.
> 
> **Overview**
> **Expands the framework integration docs** (Angular, React, Svelte,
Vue) from brief install notes into self-contained guides with concrete
TypeScript-centric examples for initializing HyperFormula, surfacing
calculated values in each framework’s reactivity model, and cleaning up
via the appropriate lifecycle hook.
> 
> Adds SSR-specific notes for Angular Universal, Next.js, Nuxt, and
SvelteKit, and standardizes demo links by switching Stackblitz URLs to
Vue-bound `<a :href>` so the cache-busting query param renders correctly
in VuePress (also applied to `custom-functions`).
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
1ecce54. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Kuba Sekowski <jakub.sekowski@handsontable.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…#1669)

## Summary
- Reframe [docs/guide/ai-sdk.md](docs/guide/ai-sdk.md) around a
HyperFormula + Vercel AI SDK integration with a single integrated
`generateText` example as the only code block.
- Mark the SDK as an unreleased prototype via a top-of-page warning
callout, and add a prominent waitlist CTA with the existing HubSpot
form.
- Rename the sidebar entry in
[docs/.vuepress/config.js](docs/.vuepress/config.js) to "Integration
with Vercel AI SDK".

Closes [HF-53](https://app.clickup.com/t/86c7upjar). Supersedes #1667.

## Test plan
- [ ] `npm run docs:dev`, open `/guide/ai-sdk`, confirm sidebar reads
"Integration with Vercel AI SDK" and the prototype callout sits above
the fold.
- [ ] Confirm the Vercel `generateText` snippet is the only code block
and the page no longer carries Install / Setup / All options /
TypeScript sections.
- [ ] Click the waitlist link and external links (Vercel docs, GitHub,
npm); click internal links to built-in / custom functions guides.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: documentation-only changes (sidebar label and guide content)
with no runtime or API behavior impact.
> 
> **Overview**
> Reframes `docs/guide/ai-sdk.md` as **HyperFormula tools for the Vercel
AI SDK**, adding a top-of-page *prototype/not-yet-released* warning, a
single `generateText`-based example, updated use cases, and a waitlist
CTA plus relevant links.
> 
> Renames the guide’s sidebar entry in `docs/.vuepress/config.js` from
“HyperFormula AI SDK” to **“Integration with Vercel AI SDK”**.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
3eb3e85. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

Co-authored-by: Joseph Petty <greenflux@Josephs-MacBook-Pro.local>
## Summary

Refines the three AI-integration landing pages — Vercel AI SDK,
LangChain/LangGraph, and MCP — so they share a single consistent voice,
structure, and call to action, and so it is unmistakable that none of
these integrations are installable yet.
Resolves [HF-53](https://app.clickup.com/t/9015210959/HF-53).

## Why

Before this change the three pages drifted in three different
directions:
- Only the AI SDK page warned readers that nothing was available yet —
the LangChain and MCP pages read like a shipped product.
- Page depth varied wildly (the LangChain and MCP pages were ~50 lines
and missing both safety and links sections; the AI SDK page was much
richer).
- The LangChain page used a Python code example, even though
HyperFormula is a TypeScript/JS-only library — misleading for readers.
- "What it does" and "Use cases" were framed differently on each page
(action-shaped vs. domain-shaped vs. host-shaped), hiding the fact that
all three integrations expose the same capabilities to an agent.
- The CTA varied between "Join the waitlist", "Sign up for beta access",
and "Drop your email", with no consistent framing of the value of
signing up.

## What changed

### Shared page template (applied to all three pages)

Every page now follows the same section order:
1. Title + one-line tagline
2. **"Not available yet — coming soon"** warning admonition (identical
wording on all three pages, with bolded "cannot be installed or used
today")
3. `## What it does` — 4 capability bullets (identical wording on all
three pages)
4. `## Example` — one short, idiomatic JS/TS example
5. `## Use cases` — 5 jobs-to-be-done bullets (identical on AI SDK and
LangChain; MCP gets one extra leading bullet — see below)
7. `## Get early access` — identical CTA admonition framing sign-up as
both *value to the user* (try it before the public release) and *value
to us* (signals demand and shapes priorities)
8. `## Links` — uniform list

### "What it does" — now identical across all three pages

- "Evaluate formulas deterministically"
- "Read and write cells and ranges"
- "Trace dependencies"
- "400+ built-in functions out of the box" (newly surfaced — previously
buried inside one LangChain use case despite being HF's biggest
differentiator)

### "Use cases" — now nearly identical across all three pages

Shared 5-bullet list (Spreadsheet Q&A, what-if and forecasting, validate
and clean data, formulas from natural language, financial modeling and
reporting).

### Per-page specifics

- **`docs/guide/ai-sdk.md`** — kept as the strongest of the three;
warning + CTA + section names harmonized; "Planned for the beta" →
"Planned for the first release".
- **`docs/guide/integration-with-langchain.md`** — full rewrite: removed
the misleading Python example, added a LangGraph `createReactAgent` JS
example mirroring the AI SDK one, added Safety/Links sections.
- **`docs/guide/mcp-server.md`** — full rewrite: replaced the
prose-style chat snippet with a concrete `npx -y @hyperformula/mcp` +
client-config example, added Safety/Links sections, swapped "Beta
access" CTA for the standardized "Get early access" admonition.

### Minor drive-by

- `docs/guide/types-of-values.md` — dropped a stray `excel` language tag
on a fenced code block that VitePress does not recognize.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk documentation-only update that rewrites/aligns three
integration guides and tweaks one code fence; no runtime or API behavior
changes.
> 
> **Overview**
> Refactors the `ai-sdk`, `LangChain/LangGraph`, and `MCP server` guide
pages to a consistent structure and voice, **explicitly stating the
integrations are not yet available** and pointing readers to a unified
early-access signup CTA.
> 
> Updates each page’s capability and use-case messaging to match,
replaces the LangChain example with an idiomatic JS/LangGraph snippet,
and expands the MCP page with concrete `npx` run + client config
examples plus a standardized `Links` section.
> 
> Separately, fixes a docs formatting issue in `types-of-values.md` by
removing an unsupported `excel` code-fence language tag.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
a759bb4. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
@sequba sequba marked this pull request as ready for review May 11, 2026 13:58
@sequba sequba marked this pull request as draft May 11, 2026 14:30
@sequba sequba marked this pull request as ready for review May 12, 2026 08:43
@netlify
Copy link
Copy Markdown

netlify Bot commented May 14, 2026

Deploy Preview for hyperformula-dev-docs ready!

Name Link
🔨 Latest commit 3a286f6
🔍 Latest deploy log https://app.netlify.com/projects/hyperformula-dev-docs/deploys/6a05bbd4809aae00088d21f4
😎 Deploy Preview https://deploy-preview-1671--hyperformula-dev-docs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 3a286f6. Configure here.

*/
module.exports = {
base: '/docs/',
dest: 'docs/.vuepress/dist/docs',
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New base path breaks existing head asset URLs

Medium Severity

The new build.config.js defaults base to '/docs/' and dest to 'docs/.vuepress/dist/docs'. VuePress 1.x does not automatically prepend base to URLs in head config items. The existing head entries (favicons, manifest, etc.) use absolute paths like '/favicon/apple-touch-icon.png', which will resolve to the server root rather than /docs/favicon/... where the assets are actually served. This causes 404s for all favicon and manifest references on the deployed site. The same applies to any other absolute-path head items (scripts, meta tags pointing to local assets).

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 3a286f6. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants