Skip to content

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

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

Function metadata API: getAvailableFunctions / getFunctionDetails (HF-249)#1692
marcin-kordas-hoc wants to merge 25 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 additive public API and catalogue surface with subtle rules (custom vs built-in, shadowing, arity drift); low runtime impact on calculation but integrators will depend on stable metadata shape and sorting.

Overview
Adds a function metadata API for formula builders and pickers: getAvailableFunctions() returns a locale-sorted short list (localizedName, canonicalName, category, shortDescription), and getFunctionDetails() adds parameters (name, description, optional), repeatLastArgs, and optional documentationUrl / examples. Both exist as static methods (language code) and instance methods (instance language).

Built-in metadata comes from a new FUNCTION_DOCS catalogue under src/interpreter/functionMetadata/ (per-category TS files, mostly generated from docs/guide/built-in-functions.md via dev-only scripts/hf249-migrate-function-docs.ts). FunctionRegistry gains captureBuiltinFunctionOwners, isBuiltinFunction, and getListableFunctionIds so catalogue docs apply only to genuine built-ins, custom plugins that shadow a built-in id are described as custom, and catalogue vs implementation arity mismatches drop the function from list and details.

Instance APIs include custom functions and aliases; static APIs cover global built-ins and aliases only. Custom entries use positional Arg1, Arg2, … and empty category/description. List order uses Intl.Collator from the language code. New public types are exported from index.ts; docs cover usage in custom-functions.md and the changelog.

Reviewed by Cursor Bugbot for commit 8207bf3. 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 (8207bf3) vs base (72205bd)

                                     testName |   base |   head |  change
-------------------------------------------------------------------------
                                      Sheet A | 486.53 | 489.37 |  +0.58%
                                      Sheet B | 155.39 | 157.94 |  +1.64%
                                      Sheet T | 135.71 | 140.67 |  +3.65%
                                Column ranges | 510.12 | 525.49 |  +3.01%
Sheet A:  change value, add/remove row/column |  15.27 |   17.7 | +15.91%
 Sheet B: change value, add/remove row/column | 136.91 | 154.47 | +12.83%
                   Column ranges - add column | 152.49 | 162.29 |  +6.43%
                Column ranges - without batch | 487.36 | 490.33 |  +0.61%
                        Column ranges - batch |  121.2 |  126.8 |  +4.62%

@netlify

netlify Bot commented Jun 9, 2026

Copy link
Copy Markdown

Deploy Preview for hyperformula-dev-docs ready!

Name Link
🔨 Latest commit 8207bf3
🔍 Latest deploy log https://app.netlify.com/projects/hyperformula-dev-docs/deploys/6a3cfb0feb3816000850639a
😎 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

@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 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 4078a56. Configure here.

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
marcin-kordas-hoc and others added 3 commits June 23, 2026 16:15
…F-249)

Address the CHANGES_REQUESTED review on #1692:

- Rename the metadata name field to localizedName (FunctionListEntry,
  FunctionDetails).
- Drop the generated syntax string; getFunctionDetails now returns the
  parameter list plus repeatLastArgs so the caller renders the syntax.
- Surface repeatLastArgs as a number on FunctionDetails instead of a
  per-parameter repeatable boolean (the last N args may repeat).
- Include custom functions and aliases: the instance methods read the
  instance's own registry; the static methods cover built-ins + aliases.
- Sort getAvailableFunctions alphabetically by localizedName.
- Verify categories against the official Excel docs categories; the ten
  with an Excel equivalent already match, three are HyperFormula-specific.
- Update the custom-functions guide and the CHANGELOG entry.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…nd repeatLastArgs (HF-249)

Address multi-reviewer findings on the function-metadata API:

- A user/custom plugin that shadows a built-in id (e.g. a custom SUM) is now
  reported as a custom function (positional params, undefined category, empty
  description) instead of borrowing the built-in's catalogue doc, and is no
  longer silently dropped on an arity mismatch. The catalogue doc is attached
  only when the registered plugin is the built-in plugin that canonically owns
  the id, checked via a built-in-plugin-ownership map derived from the same
  plugin set the catalogue was generated from.

- getAvailableFunctions now sorts under an explicit, language-derived
  Intl.Collator (BCP-47 locale from the language code) instead of the
  host-locale-dependent String.localeCompare, with the canonical name as a
  stable tiebreaker for entries sharing a localized name.

- buildCustomFunctionDetails clamps repeatLastArgs to the declared parameter
  count, so a pathological custom plugin cannot report more repeating trailing
  parameters than it has.

- Remove getCanonicalFunctionIds from the production module (its only remaining
  consumer was a test).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…-249)

buildFunctionDescriptions eagerly imported the plugin barrel to detect
built-in ownership; since HyperFormula loads the metadata builders early,
that created a module-load-order cycle crashing the bundled build
('Class extends value undefined' in the perf benchmark). Move the
built-in owner snapshot to FunctionRegistry (captured in index.ts, which
already imports the barrel to register built-ins) and expose
isBuiltinFunction; the builders no longer import the barrel. Shadow-vs-
built-in behavior is unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@marcin-kordas-hoc marcin-kordas-hoc requested a review from sequba June 24, 2026 11:12
Comment thread docs/guide/custom-functions.md Outdated
…adata (HF-249)

Per review: the metadata guide need not describe what the API does NOT return.
Keep only the repeatLastArgs explanation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@marcin-kordas-hoc marcin-kordas-hoc requested a review from sequba June 24, 2026 18:28
marcin-kordas-hoc and others added 2 commits June 25, 2026 09:26
…/examples on FunctionDoc (HF-249)

Add optional documentationUrl/examples to FunctionDoc and surface them in
getFunctionDetails (falling back to ''/[] when absent). Author SUM and SUMIF
as reference functions with real parameter descriptions, examples and a
documentation link so the Formula Builder team can test rendering of populated
metadata. The migration generator does not emit these fields; a comment guards
the two entries against regeneration.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ails (HF-249)

The custom-functions guide listed the getFunctionDetails return shape but omitted
the documentationUrl and examples fields; add them so the documented shape matches
FunctionDetails.

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

codecov Bot commented Jun 25, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.40000% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 97.17%. Comparing base (72205bd) to head (8207bf3).
⚠️ Report is 1 commits behind head on develop.

Files with missing lines Patch % Lines
src/HyperFormula.ts 98.18% 1 Missing ⚠️
...eter/functionMetadata/buildFunctionDescriptions.ts 95.83% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff            @@
##           develop    #1692    +/-   ##
=========================================
  Coverage    97.16%   97.17%            
=========================================
  Files          176      192    +16     
  Lines        15322    15446   +124     
  Branches      3387     3412    +25     
=========================================
+ Hits         14887    15009   +122     
- Misses         435      437     +2     
Files with missing lines Coverage Δ
src/index.ts 100.00% <100.00%> (ø)
src/interpreter/FunctionRegistry.ts 99.41% <100.00%> (+0.04%) ⬆️
...nterpreter/functionMetadata/FunctionDescription.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%> (ø)
...rpreter/functionMetadata/categories/information.ts 100.00% <100.00%> (ø)
...interpreter/functionMetadata/categories/logical.ts 100.00% <100.00%> (ø)
... and 9 more
🚀 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.

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