Skip to content

Function metadata API: getAvailableFunctions / getFunctionDetails (HF-249)#1692

Open
marcin-kordas-hoc wants to merge 38 commits into
developfrom
feature/hf-249-function-metadata-api
Open

Function metadata API: getAvailableFunctions / getFunctionDetails (HF-249)#1692
marcin-kordas-hoc wants to merge 38 commits into
developfrom
feature/hf-249-function-metadata-api

Conversation

@marcin-kordas-hoc

@marcin-kordas-hoc marcin-kordas-hoc commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds a two-tier public API for retrieving function metadata, intended for a Formula Builder / function picker:

  • HyperFormula.getAvailableFunctions(code) (static) / hfInstance.getAvailableFunctions() (instance) → FunctionListEntry[] — a short list sorted alphabetically by localized name: localizedName, canonicalName, category, shortDescription.
  • HyperFormula.getFunctionDetails(canonicalName, code) (static) / hfInstance.getFunctionDetails(canonicalName) (instance) → FunctionDetails | undefined — the same fields plus the ordered parameters list (each name, description, optional) and repeatLastArgs (how many trailing parameters repeat; 0 for a fixed arg list). No pre-rendered syntax string — the caller renders it from parameters + repeatLastArgs.

Built-in functions and their aliases are included. Custom (user-registered) functions are instance-scoped, so they are listed by the instance methods, not the static ones; a custom function has category: undefined, an empty shortDescription, and positional parameter names (Arg1, Arg2, …). A custom function that shadows a built-in id is reported as the custom function (never the built-in’s catalogue metadata).

Catalogue

The 363-function catalogue lives in src/interpreter/functionMetadata/categories/ (generated from docs/guide/built-in-functions.md by a dev-only script; not shipped — tsconfig include is ["src"]). Categories use the full-word names from the official Excel docs; Array manipulation, Matrix functions and Operator are HyperFormula-specific. Parameter names/optionality follow the implementation arity in implementedFunctions; a catalogue-vs-implementation arity mismatch drops the function from both list and details so they never disagree.

Tests

Paired tests PR: handsontable/hyperformula-tests#14 (branch feature/hf-249-function-metadata-api):

  • public API: static + instance, i18n, built-in aliases, custom functions (list + details, positional params, category: undefined), custom alias, instance-vs-static scoping
  • coverage parity: FUNCTION_DOCS keys == canonical set (both directions); FUNCTION_CATEGORIES shape
  • parameter consistency: count == arity, unique non-empty names, numeric repeatLastArgs (SUM=1, SUMIFS=2, SUMIF=0)
  • shadowed-built-in reported as custom (matching + mismatched arity); custom repeatLastArgs clamp
  • deterministic ordering: alphabetical by localizedName with canonicalName tiebreaker (locale-aware), non-Latin names

MVP scope

parameters[].description, documentationUrl, and examples are present but empty; authored in a later phase.

Notes

  • Sort order: alphabetical by localized name, canonicalName tiebreaker, via Intl.Collator from the language’s locale (deterministic across environments).
  • Empty language-pack translations fall back to the canonical id.

Note

Medium Risk
Large new public API surface on HyperFormula and FunctionRegistry init behavior, but read-only metadata with no formula evaluation changes; edge cases (aliases, shadows, drift) are explicitly gated.

Overview
Introduces getAvailableFunctions() and getFunctionDetails() on HyperFormula (static, language code + built-ins/aliases only) and on each instance (instance language + custom plugins). Responses include localized names, categories, short descriptions, parameters (with optionality and repeatLastArgs), plus optional docs URLs and examples where authored.

A new FUNCTION_DOCS catalogue under src/interpreter/functionMetadata/ holds per-function metadata; a dev-only scripts/hf249-migrate-function-docs.ts can regenerate category files from docs/guide/built-in-functions.md. FunctionRegistry now snapshots built-in plugin ownership at init (captureBuiltinFunctionOwners) so shadowed built-in ids and catalogue drift (arity mismatch) are handled consistently—custom overrides and bad catalogue rows are omitted or reported as custom-only metadata.

Public types FunctionListEntry, FunctionDetails, and related types are exported from the package entry. Guides and changelog document the API; static methods exclude globally registered custom plugins, while instance methods include them with sparse metadata (Arg1, …).

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

…c API (HF-249)

Add static and instance getAvailableFunctions and getFunctionDetails to
HyperFormula, backed by the function metadata catalogue. Instance methods
delegate to the static ones using the configured language. Re-export the
public catalogue types from the package entry point.
Replace the seeded catalogue with all 363 canonical built-ins, generated from
docs/guide/built-in-functions.md by scripts/hf249-migrate-function-docs.ts (dev-only,
not shipped). Parameter names come from the Syntax column but their count and
optionality follow the implementation arity; repeating groups collapse and duplicate
names are disambiguated. Also fall back to the canonical id when a language pack leaves
a function name empty (e.g. SWITCH in several locales).
…-249)

Add a CHANGELOG entry for the new built-in function metadata API, and a
"Function metadata" section to the custom functions guide clarifying that the
catalogue covers built-ins only — custom functions are absent from
getAvailableFunctions() and getFunctionDetails() returns undefined for them.
@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown

Performance comparison of head (d256895) vs base (fd04f77)

                                     testName |   base |   head | change
------------------------------------------------------------------------
                                      Sheet A | 629.98 | 602.16 | -4.42%
                                      Sheet B | 219.96 | 213.39 | -2.99%
                                      Sheet T | 194.32 |  189.1 | -2.69%
                                Column ranges | 606.98 | 588.64 | -3.02%
Sheet A:  change value, add/remove row/column |  22.52 |  22.14 | -1.69%
 Sheet B: change value, add/remove row/column | 188.49 | 179.79 | -4.62%
                   Column ranges - add column | 208.34 | 203.28 | -2.43%
                Column ranges - without batch | 639.68 | 661.69 | +3.44%
                        Column ranges - batch | 164.56 | 148.98 | -9.47%

@netlify

netlify Bot commented Jun 9, 2026

Copy link
Copy Markdown

Deploy Preview for hyperformula-dev-docs ready!

Name Link
🔨 Latest commit d256895
🔍 Latest deploy log https://app.netlify.com/projects/hyperformula-dev-docs/deploys/6a58dd933a99070008e5d793
😎 Deploy Preview https://deploy-preview-1692--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.

@marcin-kordas-hoc
marcin-kordas-hoc force-pushed the feature/hf-249-function-metadata-api branch from 8983d26 to 3f8857b Compare June 10, 2026 03:21
marcinkordas

This comment was marked as resolved.

@marcin-kordas-hoc
marcin-kordas-hoc marked this pull request as ready for review June 10, 2026 10:54
Comment thread src/HyperFormula.ts Outdated
…ith getFunctionDetails (HF-249)

getAvailableFunctions derived its id set from each plugin class's static implementedFunctions, so an unregistered built-in (or a registry mutation) could still appear in the list while getFunctionDetails returned undefined for it. Gate the list on FunctionRegistry.getFunctionPlugin(id) — the same resolution getFunctionDetails uses — so list and details never disagree. (Cursor Bugbot, #1692.)
Comment thread src/HyperFormula.ts Outdated
Comment thread src/HyperFormula.ts Outdated
…tFunctionDetails agree (HF-249)

getAvailableFunctions filtered on documented+registered but not the catalogue-vs-implementation arity check that getFunctionDetails applies, so a drifted function could appear in the list yet return undefined from details. Extract resolveListableMetadata (documented + registered + arity-consistent) and use it in both. (Cursor, #1692.)
@marcin-kordas-hoc
marcin-kordas-hoc requested a review from sequba June 10, 2026 13:52
marcin-kordas-hoc and others added 2 commits June 23, 2026 07:45
…249)

Align parameter display names in the generated function-metadata catalogue
with their Title-Case siblings:
- financial.ts: CUMIPMT `type` -> `Type` (matches CUMPRINC); RATE `guess` -> `Guess`
- statistical.ts: BESSELI/J/K/Y `x`,`n` -> `X`,`N`

Also add an instance-method example to the "Function metadata" section of
docs/guide/custom-functions.md so the "available both as static and instance
methods" claim is backed by a snippet.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@qunabu

qunabu commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Comment thread src/interpreter/functionMetadata/FunctionDescription.ts Outdated
Comment thread src/interpreter/functionMetadata/FunctionDescription.ts Outdated
Comment thread src/interpreter/functionMetadata/FunctionDescription.ts
Comment thread src/interpreter/functionMetadata/FunctionDescription.ts Outdated
Comment thread src/interpreter/functionMetadata/FunctionDescription.ts Outdated
Comment thread docs/guide/custom-functions.md Outdated
Comment thread CHANGELOG.md Outdated
Comment thread src/HyperFormula.ts
Comment thread docs/guide/custom-functions.md Outdated
@sequba

sequba commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

@cursor fix the review comment

@cursor

cursor Bot commented Jul 14, 2026

Copy link
Copy Markdown

Taking a look!

Open in Web Open in Cursor 

- Add XIRR to Financial category with Values, Dates, Guess parameters
- Add VSTACK and HSTACK to Array manipulation category with Array1 parameter
- Move Function metadata section from custom-functions.md to built-in-functions.md
- Fixes Bugbot review: Missing catalogue mislabels builtins

Co-authored-by: Kuba Sekowski <sequba@users.noreply.github.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

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 using default effort 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 c65115b. Configure here.

Comment thread src/HyperFormula.ts
cursoragent and others added 5 commits July 14, 2026 11:44
Static getAvailableFunctions and getFunctionDetails now filter out
custom plugins registered via HyperFormula.registerFunctionPlugin,
returning only built-in functions and their aliases as documented.

Co-authored-by: Kuba Sekowski <sequba@users.noreply.github.com>
Add note to custom-functions.md explaining that globally-registered
custom plugins (via registerFunctionPlugin) are available in all
instances but don't appear in static metadata API methods.

Co-authored-by: Kuba Sekowski <sequba@users.noreply.github.com>
…dsontable/hyperformula into feature/hf-249-function-metadata-api
sequba and others added 2 commits July 14, 2026 15:36
…(HF-249) (#1709)

<!-- CURSOR_AGENT_PR_BODY_BEGIN -->
### Context

Addresses a code-review finding on #1692: the function-metadata
catalogue mixed several parameter-name conventions, which surface
directly in a function-picker UI. Even closely-related functions
disagreed — `SUMIF` used `Range, Criteria, Sumrange`, `SUMIFS` used
`Sum_Range, Criterion_range1, Criterion1`, `AVERAGEIF` used `Range,
Criterion, Average_Range` — mixing Title-case, `snake_Case`, and run-on
tokens.

This normalizes **every** `FunctionDoc` parameter name to `snake_case`
so the catalogue is internally consistent.

**What changed**

- All 172 unique parameter names across the 13 `categories/*.ts` files
are now `snake_case` (lowercase words joined by `_`, camelCase/acronym
boundaries split, separators unified, trailing digits kept attached:
`Number1`/`Number_1` → `number1`).
- Run-on tokens the docs left unsplit are segmented so siblings agree:
`Sumrange` → `sum_range` (matches `SUMIFS`), `Searchcriterion` →
`search_criterion` (matches `VLOOKUP`/`HLOOKUP`), plus `logical_value`,
`date_string`, `time_string`, `start_date`, `minimum_length`,
`lower_bound`, `upper_bound`, `number_x`, `number_y`.
- The migration generator (`scripts/hf249-migrate-function-docs.ts`) now
emits `snake_case` via a shared, exported `toSnakeCase` helper (+ a
small segmentation table), so a future regeneration stays consistent.
Its `main()` is guarded with `require.main === module` so the helper can
be imported without side effects.
- **Not touched:** parameter `description`s, `examples`,
`documentationUrl`, categories, short descriptions, ordering.
Custom-function positional names (`Arg1`, `Arg2`, …) are unchanged —
they are a documented, self-consistent placeholder for user functions
that ship no metadata (see open question below).

### How did you test your changes?

- `tsc --noEmit` — clean.
- `eslint` on the changed files — 0 errors.
- `test/smoke.spec.ts` — 4/4 pass.
- Ad-hoc runtime checks against the built API:
- every catalogue **and** `getFunctionDetails` parameter name matches
`^[a-z][a-z0-9]*(_[a-z0-9]+)*$`;
- names are unique within each function (no collisions introduced by the
transform);
- `getAvailableFunctions`/`getFunctionDetails` list↔details parity still
holds;
- `SUMIF` & `SUMIFS` both expose `sum_range`; `MATCH` & `VLOOKUP` both
expose `search_criterion`;
  - custom-function details still report `Arg1`, `Arg2`.
- Ran the generator to confirm it produces identical parameter names to
this hand-applied transform (the only regen deltas are unrelated
pre-existing drift — alphabetical re-sorting of manually-added
`HSTACK`/`XIRR`, the hand-authored `SUM`/`SUMIF` fields, and a stale
`TEXT` description — so the regen output was discarded).

### Types of changes

- [ ] 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

### Related issues:

1. Follow-up to #1692 (HF-249); targets that branch.

### Notes for reviewers

- **Paired tests:** the private test suite (`hyperformula-tests#14`)
asserts specific parameter names (e.g. `SUMIF` params); those
expectations need updating to the new `snake_case` names.
- **Open question — custom functions:** the request was "snake_case for
all param names". I scoped this to the catalogue and left the runtime
custom-function placeholders as the documented `Arg1`/`Arg2`. If you'd
also like those lowercased (`arg1`/`arg2`), it's a 1-line change in
`buildCustomFunctionDetails` plus a `custom-functions.md` wording update
— say the word.
- **Segmentation calls** (`sumrange`→`sum_range`, etc.) are the only
editorial decisions here; everything else is mechanical.

<!-- CURSOR_AGENT_PR_BODY_END -->

<div><a
href="https://cursor.com/agents/bc-51ff732c-3307-42ef-aa24-7fb0dc332ce9"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/assets/images/open-in-web-light.png"><img
alt="Open in Web" width="114" height="28"
src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a>&nbsp;<a
href="https://cursor.com/background-agent?bcId=bc-51ff732c-3307-42ef-aa24-7fb0dc332ce9"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img
alt="Open in Cursor" width="131" height="28"
src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a>&nbsp;</div>

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Kuba Sekowski <sequba@users.noreply.github.com>
…es (HF-249) (#1710)

<!-- CURSOR_AGENT_PR_BODY_BEGIN -->
### Context

Addresses a code-review finding on #1692: `getAvailableFunctions` can
throw a `RangeError` for a caller-registered, malformed language code.

`buildAvailableFunctions` built its sort collator with `new
Intl.Collator(toBcp47Locale(code))`. `toBcp47Locale` only hyphenates the
canonical `<ll><RR>` shape and passes any other string through
unchanged, and `registerLanguage` performs **no** shape validation on
the code. `Intl.Collator` throws a `RangeError` on a *structurally
invalid* language tag (it does **not** silently fall back to the default
locale). So a caller who registers an underscore-style code such as
`'pt_BR'` (or `'en_US'`, `'x'`, `'12'`) and then calls
`getAvailableFunctions` (static **or** instance) crashes.

Built-in language codes are all safe, so this only affects
consumer-registered malformed codes → important, not critical.

The `toBcp47Locale` JSDoc was also wrong: it claimed unrecognized tags
"fall back to the default locale," which `Intl.Collator` does not do for
invalid tags.

### Fix

- Extract `createLocaleCollator(languageCode)` which wraps the
`Intl.Collator` construction in a `try/catch` and falls back to the
environment-default collator (`new Intl.Collator()`) on `RangeError`, so
listing functions never crashes on a non-BCP-47 code.
- Use it in `buildAvailableFunctions`.
- Correct the `toBcp47Locale` JSDoc to describe the real behavior
(invalid tags throw; the throw is handled by `createLocaleCollator`).

`getFunctionDetails` is unaffected — it does not sort and never
constructs a collator.

### How did you test your changes?

- Reproduced the crash before the fix: registering `'pt_BR'` then
calling `getAvailableFunctions('pt_BR')` threw `RangeError: Incorrect
locale information provided`.
- After the fix, `'pt_BR'`, `'en_US'`, `'x'`, and `'12'` each return the
full, alphabetically-sorted 419-entry list; well-formed `'enGB'` is
unchanged.
- Confirmed via Node that `new Intl.Collator('pt_BR'|'en_US'|'x'|'12')`
throw while `'zz-ZZ'`/`'qqq'` do not.
- `tsc --noEmit` clean; `eslint src/HyperFormula.ts` 0 errors;
`test/smoke.spec.ts` 4/4.

### Types of changes

- [ ] Breaking change (a fix or a feature because of which an existing
functionality doesn't work as expected anymore)
- [ ] New feature or improvement (a non-breaking change that adds
functionality)
- [x] 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

### Related issues:

1. Follow-up to #1692 (HF-249); targets that branch.

### Notes for reviewers

- Behavior on a malformed code is now "sort using the default collator"
rather than throwing. The alternative (validating codes in
`registerLanguage`) would be a broader, potentially breaking change, so
it's intentionally out of scope here.
- A unit test for this belongs in the paired private suite
(`hyperformula-tests`): register a `'pt_BR'`-style code and assert
`getAvailableFunctions` returns a sorted list instead of throwing.

<!-- CURSOR_AGENT_PR_BODY_END -->

<div><a
href="https://cursor.com/agents/bc-51ff732c-3307-42ef-aa24-7fb0dc332ce9"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/assets/images/open-in-web-light.png"><img
alt="Open in Web" width="114" height="28"
src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a>&nbsp;<a
href="https://cursor.com/background-agent?bcId=bc-51ff732c-3307-42ef-aa24-7fb0dc332ce9"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img
alt="Open in Cursor" width="131" height="28"
src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a>&nbsp;</div>

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Kuba Sekowski <sequba@users.noreply.github.com>
marcin-kordas-hoc added a commit that referenced this pull request Jul 15, 2026
…param backticks (HF-300)

- BETA.DIST second example switched from the PDF-with-bounds form
  (=BETA.DIST(2,2,3,FALSE(),0,4) → HF 1.5 vs Excel 0.375, a known engine
  PDF-scaling bug) to the cumulative bounded form (=BETA.DIST(2,2,3,TRUE(),0,4)
  → 0.6875, matches Excel). Still exercises the optional A/B bounds args, but
  no longer ships an example whose output is wrong.
- Removed backticks from six date-and-time PARAMETER descriptions
  (nullDate/dateFormats/timeFormats). The metadata field is plain text and
  every other parameter description in the catalogue is plain prose; backticks
  rendered literally for API consumers. shortDescription markdown links are
  migrated (#1692) content and left untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Source: https://app.clickup.com/t/86caprtgj
ADR: adr/2026-07-13-hf300-function-metadata-enrichment.md
sequba and others added 2 commits July 15, 2026 08:50
A traceability audit (run during HF-300) found migrated shortDescriptions that
either misstate behavior or leak markup into the plain-text metadata API. Per
Kuba's call (Slack #hyperformula-dev, 2026-07-15) they belong on the parent
HF-249 branch, since the catalogue is becoming the single source of truth
(docs/guide generated from it at build):

- XNPV: was verbatim identical to NPV; now conveys its non-periodic/date-based nature.
- MIRR: "modified internal value" -> "modified internal rate of return".
- SPLIT/TEXT: dropped <br> + markdown (rendered literally through the API); TEXT
  now also mentions the stringifyCurrency option.
- SECH: "given angle (in radians)" -> "given value" (the argument is a plain number).
- BASE: "positive integer" -> "non-negative integer" (0 is accepted by the impl).
- typos: MROUND "neares"/"multiplicity", Fischer->Fisher, densitity->density,
  skeweness->skewness (x2).

Catalogue-only; docs/guide regenerates from these once #1699 lands.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
marcin-kordas-hoc added a commit that referenced this pull request Jul 15, 2026
…1692 refactor (HF-249)

Rebasing #1699 onto the refactored #1692 combined that branch's protected-aware
resolveFunctionMetadata (which surfaces VERSION/OFFSET) with #1692's rewritten
static getFunctionDetails, which bails at `plugin === undefined` before reaching
the protected path. Result: getAvailableFunctions listed VERSION/OFFSET but
getFunctionDetails returned undefined for them, so the docs generator threw
"No details for listed function VERSION".

Handle the protected ids explicitly in the plugin-less branch, mirroring
getAvailableFunctions, so the list and the details API agree again. Protected ids
without a catalogue doc still resolve to undefined, so both stay consistent there.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
marcin-kordas-hoc added a commit that referenced this pull request Jul 15, 2026
…ue convention (HF-249)

OFFSET was added to the catalogue on this branch before #1692 standardized every
parameter name to snake_case, so after the rebase it was the lone PascalCase entry
(Reference/Rows/Columns/Height/Width) among snake_case siblings. Align it, so
getFunctionDetails('OFFSET') and the generated table read consistently.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
marcin-kordas-hoc added a commit that referenced this pull request Jul 15, 2026
…HF-249)

Reflects the rebased catalogue: snake_case parameter names (#1692 refactor, incl.
OFFSET), the new VSTACK/HSTACK entries (#1698), and the protected VERSION/OFFSET
functions.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
marcin-kordas-hoc added a commit that referenced this pull request Jul 15, 2026
…der default (HF-300)

Addresses Kuba's #1705 review:
- documentationUrl: the builder-level `?? DEFAULT_DOCUMENTATION_URL` fallback was
  too implicit ("may become obsolete easily"). The URL is now set explicitly on
  every FunctionDoc (via the shared DEFAULT_DOCUMENTATION_URL const, relocated to
  FunctionDescription.ts), the field is required, and buildFunctionDetails reads
  doc.documentationUrl directly. No behavioural change (same URL for all built-ins).
- CHANGELOG: removed the separate HF-300 entry; the #1692 metadata-API entry covers it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Source: https://app.clickup.com/t/86caprtgj
@marcin-kordas-hoc
marcin-kordas-hoc requested a review from sequba July 16, 2026 07:40
@codecov

codecov Bot commented Jul 16, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 96.43%. Comparing base (e0e1261) to head (40b6468).

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop    #1692      +/-   ##
===========================================
- Coverage    97.16%   96.43%   -0.73%     
===========================================
  Files          176      192      +16     
  Lines        15450    15589     +139     
  Branches      3417     3447      +30     
===========================================
+ Hits         15012    15034      +22     
- Misses         438      555     +117     
Files with missing lines Coverage Δ
src/HyperFormula.ts 99.75% <100.00%> (+0.02%) ⬆️
src/index.ts 100.00% <100.00%> (ø)
src/interpreter/FunctionRegistry.ts 99.43% <100.00%> (+0.05%) ⬆️
...nterpreter/functionMetadata/FunctionDescription.ts 100.00% <100.00%> (ø)
...eter/functionMetadata/buildFunctionDescriptions.ts 100.00% <100.00%> (ø)
.../functionMetadata/categories/array-manipulation.ts 100.00% <100.00%> (ø)
...nterpreter/functionMetadata/categories/database.ts 100.00% <100.00%> (ø)
...reter/functionMetadata/categories/date-and-time.ts 100.00% <100.00%> (ø)
...rpreter/functionMetadata/categories/engineering.ts 100.00% <100.00%> (ø)
...terpreter/functionMetadata/categories/financial.ts 100.00% <100.00%> (ø)
... and 9 more

... and 2 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

marcin-kordas-hoc and others added 2 commits July 16, 2026 15:29
…iptions (HF-300) (#1705)

## What & why

HF-300 enriches the function-metadata API (`getFunctionDetails`) so
every built-in function returns, in addition to the existing short
description and parameter names:

- a **usage example** (≥1 per function),
- a **documentation URL** — a single shared URL for all functions in v1
(`https://hyperformula.handsontable.com/docs/guide/built-in-functions.html`),
and
- a **short description for each parameter**.

Everything is English (translations are a later phase; the structure is
already i18n-ready). Extends the `SUM`/`SUMIF` exemplar already on the
base branch to the whole catalogue (363 functions).

Base: `feature/hf-249-function-metadata-api` (#1692). Sibling: #1699
(docs single source).

## How

- The single documentation URL is defined once as
`DEFAULT_DOCUMENTATION_URL` in `buildFunctionDescriptions.ts` and
applied as the built-in default — not repeated per function. Custom
(user-registered) functions keep `''`.
- `examples` + per-parameter `description` authored per category file
(`categories/*.ts`). Parameter counts/names and entry order are
unchanged; only bodies were filled.

## Testing (in the paired hyperformula-tests PR)

- Coverage-parity: every listable built-in exposes the shared URL, ≥1
example, and a non-empty description for every parameter.
- Example-validity: every authored example is built in HyperFormula and
asserted not to be a parse (`#ERROR!`) or unknown-function (`#NAME?`)
error.
- Existing `SUM`/`SUMIF` assertions updated to the `.html` URL.
- Arity guard (`buildFunctionDetails`) stays green across all 363
functions.

Local gates: `tsc` (src+test) clean · `eslint` clean · full `jest` 0
failures · metadata+coverage+example-validity specs pass.

## Notes for review

- **No i18n changes — by design.** DoD scopes HF-300 to English; no
functions are added/renamed, so the 17-language-pack rule does not
apply. English-form examples show under every locale for now (accepted
"translations later" trade-off).
- **Operators** (`HF.ADD`, …) are listable built-ins, so they get
examples/descriptions per the DoD's "each function".
- **Aliases** inherit their target's authored doc automatically
(`resolveFunctionMetadata`), so they need no separate authoring.
- **Guide table untouched** → the #1699 docs drift-check stays green
(none of the new fields are rendered in the Function
ID/Description/Syntax table).
- Descriptions describe **HyperFormula's actual behavior** (verified
against the plugins), not Excel where they diverge — e.g. `MOD` result
takes the sign of the dividend, `FILTER` accepts a single row/column,
`XNPV`'s first date is the reference point.

Decisions and citations: ADR in the paired hyperformula-tests repo
(`adr/2026-07-13-hf300-function-metadata-enrichment.md`).

Source: https://app.clickup.com/t/86caprtgj

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Large, user-facing metadata expansion for every built-in via
`getFunctionDetails`, but no formula-engine behavior changes; main risk
is stale or incorrect authored docs and accidental loss if the migration
script is re-run.
> 
> **Overview**
> **HF-300** fills out the built-in `FunctionDoc` catalogue so
`getFunctionDetails` can return real **parameter descriptions**, at
least one **usage example** per function, and a shared **documentation
URL** (`.html` guide link) across the category files—not the previous
empty placeholders.
> 
> `FunctionDescription` / `buildFunctionDetails` comments and contracts
are updated to treat those fields as authored for built-ins (custom
functions still get `''` / `[]`). `buildFunctionDetails` now passes
`documentationUrl` straight from the catalogue instead of defaulting
missing values to `''`.
> 
> The HF-249 migration script and category file headers **warn that
re-running the generator wipes** hand-authored `examples` and parameter
`description` text. One wording fix: **`INT`**’s short description now
matches truncate-toward-zero behavior.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
1c6b6a9. 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.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Kuba Sekowski <sequba@users.noreply.github.com>
Co-authored-by: Kuba Sekowski <jakub.sekowski@handsontable.com>
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.

5 participants