TMP PR: Release/3.3.0#1671
Conversation
…ples in Stackblitz (#1621)
* 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 -->
✅ Deploy Preview for hyperformula-dev-docs ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ 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', |
There was a problem hiding this comment.
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)
Reviewed by Cursor Bugbot for commit 3a286f6. Configure here.


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.0release by updatingCHANGELOG.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 newbuild.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, ignorescoverage/and vendoredtest/hyperformula-tests/, bumps.nvmrcto Node 18, addsnetlify.toml, and removes the legacyMakefile.Reviewed by Cursor Bugbot for commit 3a286f6. Bugbot is set up for automated code reviews on this repo. Configure here.