From 9974cda51a6eb6060f70e74d8879dcf1dc90fb85 Mon Sep 17 00:00:00 2001 From: marcin-kordas-hoc Date: Wed, 22 Jul 2026 09:20:37 +0000 Subject: [PATCH 1/3] docs(HF-282): auto-derive function & language counts in docs The function count already auto-derived via {{ $page.functionsCount }}; add a parallel {{ $page.languagesCount }} sourced from the i18n export barrel (src/i18n/languages/index.ts), and swap the remaining hardcoded counts to the interpolated variables. - config.js: derive languagesCount once at module load from the barrel (whitespace-tolerant regex + fail-loud guard so a barrel reformat can never silently publish "0 languages"); inject $page.languagesCount. - docs: ~400/400+ -> {{ $page.functionsCount }} (index, ai-sdk, mcp-server, langchain); 17/18 -> {{ $page.languagesCount }} (index, built-in-functions, i18n-features, localizing-functions). - README (not a VuePress page): manual "over 400" + "18" (drift-resistant). Verified via docs:build: renders 418 functions / 18 languages, incl. inside markdown link text, with no un-rendered mustache in dist. Docs-only + docs-build-config: no CHANGELOG per DEV_DOCS DoD. Co-Authored-By: Claude Opus 4.8 (1M context) --- README.md | 4 ++-- docs/.vuepress/config.js | 15 +++++++++++++++ docs/guide/ai-sdk.md | 2 +- docs/guide/built-in-functions.md | 2 +- docs/guide/i18n-features.md | 2 +- docs/guide/integration-with-langchain.md | 2 +- docs/guide/localizing-functions.md | 2 +- docs/guide/mcp-server.md | 2 +- docs/index.md | 4 ++-- 9 files changed, 25 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index a2fe4f533..c2db675c2 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ HyperFormula doesn't assume any existing user interface, making it a general-pur - [Function syntax compatible with Microsoft Excel](https://hyperformula.handsontable.com/guide/compatibility-with-microsoft-excel.html) and [Google Sheets](https://hyperformula.handsontable.com/guide/compatibility-with-google-sheets.html) - High-speed parsing and evaluation of spreadsheet formulas -- [A library of ~400 built-in functions](https://hyperformula.handsontable.com/guide/built-in-functions.html) +- [A library of over 400 built-in functions](https://hyperformula.handsontable.com/guide/built-in-functions.html) - [Support for custom functions](https://hyperformula.handsontable.com/guide/custom-functions.html) - [Support for Node.js](https://hyperformula.handsontable.com/guide/server-side-installation.html#install-with-npm-or-yarn) - [Support for undo/redo](https://hyperformula.handsontable.com/guide/undo-redo.html) @@ -49,7 +49,7 @@ HyperFormula doesn't assume any existing user interface, making it a general-pur - [Support for clipboard](https://hyperformula.handsontable.com/guide/clipboard-operations.html) - [Support for named expressions](https://hyperformula.handsontable.com/guide/named-expressions.html) - [Support for data sorting](https://hyperformula.handsontable.com/guide/sorting-data.html) -- [Support for formula localization with 17 built-in languages](https://hyperformula.handsontable.com/guide/i18n-features.html) +- [Support for formula localization with 18 built-in languages](https://hyperformula.handsontable.com/guide/i18n-features.html) - Easy integration with any front-end or back-end application - GPLv3 or a [commercial license](https://handsontable.com/get-a-quote) - Maintained by the team that stands behind the [Handsontable](https://handsontable.com/) data grid diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index 928edba20..32d9902e2 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -4,6 +4,19 @@ const footnotePlugin = require('markdown-it-footnote'); const searchBoxPlugin = require('./plugins/search-box'); const examples = require('./plugins/examples/examples'); const HyperFormula = require('../../dist/hyperformula.full'); +const fs = require('fs'); +const path = require('path'); + +// HF-282: count HF built-in languages from the i18n export barrel (source of truth): +// one `export {default as xxYY}` line per shipped language. Read once at config load — +// no dist/ dependency, so it resolves identically in `docs:dev` and `docs:build`. +const languagesCount = ( + fs.readFileSync(path.resolve(__dirname, '../../src/i18n/languages/index.ts'), 'utf8') + .match(/^export \{\s*default as \w+\}/gm) || [] +).length; +if (!languagesCount) { + throw new Error('HF-282: derived languagesCount is 0 — src/i18n/languages/index.ts barrel format changed; fix the regex in docs/.vuepress/config.js.'); +} const includeCodeSnippet = require('./plugins/markdown-it-include-code-snippet'); const searchPattern = new RegExp('^/api', 'i'); @@ -103,6 +116,8 @@ module.exports = { $page.releaseDate = HyperFormula.releaseDate // inject current HF function count as {{ $page.functionsCount }} variable $page.functionsCount = HyperFormula.getRegisteredFunctionNames('enGB').length + // inject current HF built-in language count as {{ $page.languagesCount }} variable + $page.languagesCount = languagesCount if (searchPattern.test($page.path)) { $page.frontmatter.editLink = false diff --git a/docs/guide/ai-sdk.md b/docs/guide/ai-sdk.md index e38f89c52..1e6153c9c 100644 --- a/docs/guide/ai-sdk.md +++ b/docs/guide/ai-sdk.md @@ -13,7 +13,7 @@ If you'd like to try it, [join the early access list](https://2fmjvg.share-eu1.h - **Evaluate formulas deterministically** — your agent runs any Excel-compatible formula through HyperFormula instead of asking the LLM to do math. Results are exact, reproducible, and auditable. - **Read and write cells and ranges** — the agent inspects, populates, or modifies sheet data through typed tool calls. - **Trace dependencies** — precedents and dependents are surfaced so the agent can explain how every value was derived. -- **400+ built-in functions out of the box** — the agent has access to the full Excel-compatible function set (`SUM`, `VLOOKUP`, `IRR`, `INDEX/MATCH`, and the rest), no implementation work required. +- **{{ $page.functionsCount }} built-in functions out of the box** — the agent has access to the full Excel-compatible function set (`SUM`, `VLOOKUP`, `IRR`, `INDEX/MATCH`, and the rest), no implementation work required. ## Example diff --git a/docs/guide/built-in-functions.md b/docs/guide/built-in-functions.md index d486c8e04..37c8a4e65 100644 --- a/docs/guide/built-in-functions.md +++ b/docs/guide/built-in-functions.md @@ -28,7 +28,7 @@ spreadsheet software. That is because a spreadsheet is probably the most universal software ever created. We wanted the same flexibility for HyperFormula but without the constraints of the spreadsheet UI. -Each of HyperFormula's built-in function names is available in [17 languages](localizing-functions.md#list-of-supported-languages) and [custom language packs](localizing-functions.md) can be added. +Each of HyperFormula's built-in function names is available in [{{ $page.languagesCount }} languages](localizing-functions.md#list-of-supported-languages) and [custom language packs](localizing-functions.md) can be added. The latest version of HyperFormula has an extensive collection of **{{ $page.functionsCount }}** functions grouped into categories: diff --git a/docs/guide/i18n-features.md b/docs/guide/i18n-features.md index f5c08280b..b2dd39550 100644 --- a/docs/guide/i18n-features.md +++ b/docs/guide/i18n-features.md @@ -7,7 +7,7 @@ Configure HyperFormula to match the languages and regions of your users. ## Function names and errors -Each of HyperFormula's [built-in functions](built-in-functions.md) and [errors](types-of-errors.md) is available in [18 languages](localizing-functions.md#list-of-supported-languages). +Each of HyperFormula's [built-in functions](built-in-functions.md) and [errors](types-of-errors.md) is available in [{{ $page.languagesCount }} languages](localizing-functions.md#list-of-supported-languages). You can easily [switch between languages](localizing-functions.md) ([`language`](../api/interfaces/configparams.md#language)). diff --git a/docs/guide/integration-with-langchain.md b/docs/guide/integration-with-langchain.md index 4bda40cba..99bef8704 100644 --- a/docs/guide/integration-with-langchain.md +++ b/docs/guide/integration-with-langchain.md @@ -13,7 +13,7 @@ If you'd like to try it, [join the early access list](https://2fmjvg.share-eu1.h - **Evaluate formulas deterministically** — your agent runs any Excel-compatible formula through HyperFormula instead of asking the LLM to do math. Results are exact, reproducible, and auditable. - **Read and write cells and ranges** — the agent inspects, populates, or modifies sheet data through typed tool calls. - **Trace dependencies** — precedents and dependents are surfaced so the agent can explain how every value was derived. -- **400+ built-in functions out of the box** — the agent has access to the full Excel-compatible function set (`SUM`, `VLOOKUP`, `IRR`, `INDEX/MATCH`, and the rest), no implementation work required. +- **{{ $page.functionsCount }} built-in functions out of the box** — the agent has access to the full Excel-compatible function set (`SUM`, `VLOOKUP`, `IRR`, `INDEX/MATCH`, and the rest), no implementation work required. ## Example diff --git a/docs/guide/localizing-functions.md b/docs/guide/localizing-functions.md index 1f8a752b3..d5f74084e 100644 --- a/docs/guide/localizing-functions.md +++ b/docs/guide/localizing-functions.md @@ -1,7 +1,7 @@ # Localizing functions You can localize a function's ID and error -messages. Currently, HyperFormula supports 18 languages, with British English +messages. Currently, HyperFormula supports {{ $page.languagesCount }} languages, with British English as the default. To change the language all you need to do is import and diff --git a/docs/guide/mcp-server.md b/docs/guide/mcp-server.md index 9eee7a839..7ea52c25b 100644 --- a/docs/guide/mcp-server.md +++ b/docs/guide/mcp-server.md @@ -13,7 +13,7 @@ If you'd like to try it, [join the early access list](https://2fmjvg.share-eu1.h - **Evaluate formulas deterministically** — your agent runs any Excel-compatible formula through HyperFormula instead of asking the LLM to do math. Results are exact, reproducible, and auditable. - **Read and write cells and ranges** — the agent inspects, populates, or modifies sheet data through typed tool calls. - **Trace dependencies** — precedents and dependents are surfaced so the agent can explain how every value was derived. -- **400+ built-in functions out of the box** — the agent has access to the full Excel-compatible function set (`SUM`, `VLOOKUP`, `IRR`, `INDEX/MATCH`, and the rest), no implementation work required. +- **{{ $page.functionsCount }} built-in functions out of the box** — the agent has access to the full Excel-compatible function set (`SUM`, `VLOOKUP`, `IRR`, `INDEX/MATCH`, and the rest), no implementation work required. ## Example diff --git a/docs/index.md b/docs/index.md index b98ed71eb..bcd562826 100644 --- a/docs/index.md +++ b/docs/index.md @@ -45,7 +45,7 @@ HyperFormula doesn't assume any existing user interface, making it a general-pur - [Function syntax compatible with Microsoft Excel](guide/compatibility-with-microsoft-excel.md) and [Google Sheets](guide/compatibility-with-google-sheets.md) - High-speed parsing and evaluation of spreadsheet formulas -- [A library of ~400 built-in functions](guide/built-in-functions.md) +- [A library of {{ $page.functionsCount }} built-in functions](guide/built-in-functions.md) - [Support for custom functions](guide/custom-functions.md) - [Support for Node.js](guide/server-side-installation.md#install-with-npm-or-yarn) - [Support for undo/redo](guide/undo-redo.md) @@ -53,7 +53,7 @@ HyperFormula doesn't assume any existing user interface, making it a general-pur - [Support for clipboard](guide/clipboard-operations.md) - [Support for named expressions](guide/named-expressions.md) - [Support for data sorting](guide/sorting-data.md) -- [Support for formula localization with 17 built-in languages](guide/i18n-features.md) +- [Support for formula localization with {{ $page.languagesCount }} built-in languages](guide/i18n-features.md) - Easy integration with any front-end or back-end application - GPLv3 or a [commercial license](https://handsontable.com/get-a-quote) - Maintained by the team that stands behind the [Handsontable](https://handsontable.com/) data grid From 3b741edac5ab71a4c7d5a469df58e866682ee900 Mon Sep 17 00:00:00 2001 From: marcin-kordas-hoc Date: Tue, 28 Jul 2026 12:50:15 +0000 Subject: [PATCH 2/3] fix(hf-282): register languagesCount with the .md companion resolver The companion resolver added in #1703 substitutes `{{ $page.* }}` only for an allowlist of injected keys. `languagesCount` was not on it, so the built `.md` companions and `llms-full.txt` shipped the raw mustache while the HTML rendered the number -- visible only after rebasing onto develop, which is where the resolver came from. Verified on a full docs:build: no `$page.` remains anywhere in dist; index.md, localizing-functions.md, i18n-features.md, built-in-functions.md and llms-full.txt all carry the resolved count. Co-Authored-By: Claude Opus 5 (1M context) --- docs/.vuepress/plugins/md-companions/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/.vuepress/plugins/md-companions/index.js b/docs/.vuepress/plugins/md-companions/index.js index a1a89362d..35d5ba0c0 100644 --- a/docs/.vuepress/plugins/md-companions/index.js +++ b/docs/.vuepress/plugins/md-companions/index.js @@ -13,7 +13,7 @@ const { stripVuePressSyntax } = require('./strip'); */ function resolvePageVars(md, page) { return md.replace( - /\{\{\s*\$page\.(version|buildDate|buildDateURIEncoded|releaseDate|functionsCount)\s*\}\}/g, + /\{\{\s*\$page\.(version|buildDate|buildDateURIEncoded|releaseDate|functionsCount|languagesCount)\s*\}\}/g, (m, key) => (page && page[key] != null ? String(page[key]) : m) ); } From 0607939320bd7d4e4fe38c7744d0a64ae5945484 Mon Sep 17 00:00:00 2001 From: marcin-kordas-hoc Date: Tue, 28 Jul 2026 13:21:54 +0000 Subject: [PATCH 3/3] docs(hf-282): assert the README language count against the i18n barrel The root README.md is rendered by GitHub and npm, not VuePress, so it cannot use the `{{ $page.languagesCount }}` interpolation and states the count literally. That number already rotted once: the Indonesian pack (#1674) left the README saying 17. Check it at config load against the same barrel the interpolation derives from, and fail the docs build on a mismatch or on the phrase disappearing. The function count needs no equivalent check -- "over 400" stays true as functions are added. Co-Authored-By: Claude Opus 5 (1M context) --- docs/.vuepress/config.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index 7c614b3c8..90d1cad06 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -17,6 +17,22 @@ const languagesCount = ( if (!languagesCount) { throw new Error('HF-282: derived languagesCount is 0 — src/i18n/languages/index.ts barrel format changed; fix the regex in docs/.vuepress/config.js.'); } + +// HF-282: the root README.md is rendered by GitHub and npm, not VuePress, so it cannot +// use the `{{ $page.languagesCount }}` interpolation and states the count literally. +// Assert it against the barrel so it cannot rot unnoticed — it already did once, when +// the Indonesian pack (#1674) left the README saying 17. The function count needs no +// such check: "over 400" stays true as functions are added. +const readmeLanguagesMatch = fs + .readFileSync(path.resolve(__dirname, '../../README.md'), 'utf8') + .match(/(\d+) built-in languages/); +if (!readmeLanguagesMatch) { + throw new Error('HF-282: could not find the " built-in languages" phrase in README.md — if the wording changed on purpose, update this check in docs/.vuepress/config.js.'); +} +if (Number(readmeLanguagesMatch[1]) !== languagesCount) { + throw new Error(`HF-282: README.md says ${readmeLanguagesMatch[1]} built-in languages but src/i18n/languages/index.ts exports ${languagesCount} — update README.md.`); +} + const includeCodeSnippet = require('./plugins/markdown-it-include-code-snippet'); const mdCompanions = require('./plugins/md-companions');