Function metadata API: getAvailableFunctions / getFunctionDetails (HF-249) - #1692
Function metadata API: getAvailableFunctions / getFunctionDetails (HF-249)#1692marcin-kordas-hoc wants to merge 44 commits into
Conversation
…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.
Performance comparison of head (d42080e) vs base (3b0ebc5) |
✅ Deploy Preview for hyperformula-dev-docs ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
8983d26 to
3f8857b
Compare
…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.)
…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.)
…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>
|
Task linked: HF-249 HF function documentation available via API |
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
…(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> <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> </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> <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> </div> Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Kuba Sekowski <sequba@users.noreply.github.com>
…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
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>
…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>
…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>
…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
…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>
The shared documentation-URL constant was dropped during the #1705 merge's conflict resolution, so the paired metadata tests (get-available-functions and function-metadata-enrichment) fail to compile (TS2305: no exported member). Restore it verbatim from the HF-300 branch. Base built-ins already carry the .html URL and protected OFFSET/VERSION are excluded from the metadata API, so this alone greens the pair. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Empty commit to force a fresh cross-repo test run that fetches the current hyperformula-tests feature/hf-249-function-metadata-api (rename + dev_docs + guard cleanup); prior reruns raced an intermediate tests SHA. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Merging develop into this branch brought the SORT (HF-69) and UNIQUE (HF-68) plugins, which are listable but had no FUNCTION_DOCS catalogue entries, so the metadata-enrichment coverage flagged them as offenders (missing documentation URL, examples, and parameter descriptions). Added both under "Array manipulation" with authored parameter descriptions and examples, matching the plugin arity (SORT: 4 params, UNIQUE: 3). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want higher recall? High effort reviews run extra passes and find more bugs. A team admin can switch effort levels in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit d42080e. Configure here.
| */ | ||
| export function isParameterOptional(arg: FunctionArgument | undefined): boolean { | ||
| return arg?.optionalArg === true || arg?.defaultValue !== undefined | ||
| } |
There was a problem hiding this comment.
Wrong optionality for SHEET/SHEETS
Medium Severity
getFunctionDetails reports the SHEET and SHEETS argument as not optional because isParameterOptional only checks optionalArg/defaultValue, and those implementations omit both. Both functions still accept zero arguments via runFunctionWithReferenceArgument, and the catalogue copy already describes the argument as optional, so Formula Builder consumers get a contradictory required flag for valid SHEET() / SHEETS() calls.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit d42080e. Configure here.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## develop #1692 +/- ##
===========================================
- Coverage 97.21% 96.66% -0.56%
===========================================
Files 178 194 +16
Lines 15611 15750 +139
Branches 3429 3458 +29
===========================================
+ Hits 15177 15225 +48
- Misses 426 507 +81
- Partials 8 18 +10
🚀 New features to boost your workflow:
|


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 orderedparameterslist (eachname,description,optional) andrepeatLastArgs(how many trailing parameters repeat;0for a fixed arg list). No pre-rendered syntax string — the caller renders it fromparameters+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 emptyshortDescription, 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 fromdocs/guide/built-in-functions.mdby a dev-only script; not shipped —tsconfigincludeis["src"]). Categories use the full-word names from the official Excel docs;Array manipulation,Matrix functionsandOperatorare HyperFormula-specific. Parameter names/optionality follow the implementation arity inimplementedFunctions; 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):category: undefined), custom alias, instance-vs-static scopingFUNCTION_DOCSkeys == canonical set (both directions);FUNCTION_CATEGORIESshaperepeatLastArgs(SUM=1, SUMIFS=2, SUMIF=0)repeatLastArgsclamplocalizedNamewithcanonicalNametiebreaker (locale-aware), non-Latin namesMVP scope
parameters[].description,documentationUrl, andexamplesare present but empty; authored in a later phase.Notes
canonicalNametiebreaker, viaIntl.Collatorfrom the language’s locale (deterministic across environments).Note
Medium Risk
Large new public API surface and metadata catalogue tied to implementation arity; behavior around aliases, custom overrides, and sorting must stay stable for integrators.
Overview
Adds a function metadata API for building pickers and reference UIs:
getAvailableFunctions()returns a localized, alphabetically sorted short list;getFunctionDetails()returns full parameter metadata (names, descriptions, optionality,repeatLastArgs) without a pre-built syntax string.Static methods cover built-in functions and aliases for a given language code; instance methods use the instance language and also include custom plugins, with minimal metadata (
Arg1, …) when no catalogue entry exists.FunctionRegistrynow snapshots built-in ownership so a user plugin that shadows a built-in id is described as custom, not with stale built-in docs; catalogue arity drift omits the function from both list and details.Ships a large
FUNCTION_DOCScatalogue undersrc/interpreter/functionMetadata/(per-category files, composed inindex.ts), plus a dev-onlyscripts/hf249-migrate-function-docs.tsregenerator frombuilt-in-functions.md. Public typesFunctionListEntry,FunctionDetails, andFunctionCategoryare exported from the package entry.Reviewed by Cursor Bugbot for commit d42080e. Bugbot is set up for automated code reviews on this repo. Configure here.