Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- Changed `getAvailableFunctions()` and `getFunctionDetails()` to describe only the functions the instance's license key includes, so they no longer advertise a function that would evaluate to a `#LIC!` error. A missing, invalid, or expired key does not shorten the list. [#1731](https://github.com/handsontable/hyperformula/pull/1731)
- Changed the parser for the new proprietary license keys to the entitlement key format (a human-readable text ending with a machine-readable block in square brackets), following its upstream specification. This replaces the tagged key format, which was never issued to anyone. Classic 25-character license keys and `gpl-v3` are unaffected. [#1740](https://github.com/handsontable/hyperformula/pull/1740)
- Changed the license capability tokens to be matched case-insensitively, and added support for the packaging group-token vocabulary (`fun:all`, `fun:<family>.<A|B|C>`, and per-function `fun:<FUNCTION_NAME>` tokens) alongside the existing package tokens (`functions_1`–`functions_4` and the add-ons). A key worded in either vocabulary grants the same functions. [#1741](https://github.com/handsontable/hyperformula/pull/1741)
- Changed the `getRegisteredFunctionNames()` instance method to list exactly the functions the instance can evaluate, the same way `getAvailableFunctions()` does: the protected built-ins are now included, and a function the instance's license key does not include is no longer listed. A missing, invalid, or expired key does not shorten the list. [#1743](https://github.com/handsontable/hyperformula/pull/1743)

### Deprecated

- Deprecated the static `HyperFormula.getRegisteredFunctionNames()` method; it will be removed in one of the next major releases. Use the instance method of the same name instead — a static method has no engine, and therefore no license key or configuration, in scope, so it can only answer for the function registry as a whole. The two are not interchangeable: the static one translates into any registered language without an engine, so migrating means building one, for example `HyperFormula.buildEmpty({ language: 'plPL' }).getRegisteredFunctionNames()`. [#1743](https://github.com/handsontable/hyperformula/pull/1743)

## [3.4.0] - 2026-08-10

Expand All @@ -31,6 +36,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- Added an Indonesian (Bahasa Indonesia) language pack. [#1674](https://github.com/handsontable/hyperformula/pull/1674)
- Added a `stringifyCurrency` config option that lets you plug in a custom currency formatter for the `TEXT` function. [#1145](https://github.com/handsontable/hyperformula/issues/1145)

### Removed

- **Breaking change**: Removed the static `HyperFormula.getAvailableFunctions()` and `HyperFormula.getFunctionDetails()` methods. Use the instance methods of the same names, added in this release: a static method has no engine, and therefore no configuration, in scope, so it can only answer for the package as a whole. This entry was missing from the 3.4.0 release notes and is added retroactively. [#1724](https://github.com/handsontable/hyperformula/pull/1724)

### Fixed

- Fixed the behavior of `MATCH`, `VLOOKUP`, `HLOOKUP`, and `XLOOKUP` functions when the search range contained empty cells. [#1697](https://github.com/handsontable/hyperformula/pull/1697)
Expand Down
12 changes: 7 additions & 5 deletions docs/guide/license-key.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,12 @@ If your key grants only part of the library, then:
[error value](types-of-errors.md). Everything else in the sheet keeps calculating.
* An API method your key doesn't include throws a `LicenseCapabilityMissingError` when you call
it. Getters never throw; `copy()` and `cut()` do, because they belong to the clipboard feature.
* [`getAvailableFunctions()`](../api/classes/hyperformula.md#getavailablefunctions) and
[`getFunctionDetails()`](../api/classes/hyperformula.md#getfunctiondetails) describe only the
functions your key includes, so a function picker built from them never offers a function that
then fails.
* [`getAvailableFunctions()`](../api/classes/hyperformula.md#getavailablefunctions),
[`getFunctionDetails()`](../api/classes/hyperformula.md#getfunctiondetails) and the instance
[`getRegisteredFunctionNames()`](../api/classes/hyperformula.md#getregisteredfunctionnames)
describe only the functions your key includes, so a function picker built from them never offers
a function that then fails. The static method of the same name has no engine, and therefore no
key, in scope: it answers for the whole package and is deprecated.

Custom functions you register yourself are available whatever your key grants, as long as they use
an id of their own. The licence covers built-in ids, so a plugin registered under a built-in id your
Expand Down Expand Up @@ -105,7 +107,7 @@ If your license key is missing, invalid, or expired, you see a
corresponding notification in the console.

In that case every licence-gated function call evaluates to a `#LIC!` error — but no API method
starts throwing, and `getAvailableFunctions()` still describes the full set of functions. A key
starts throwing, and the three listing methods above still describe the full set of functions. A key
problem never narrows what the library reports it can do.

Arithmetic keeps working: operators such as `=A1+B1` are not function calls, so nothing gates them.
Expand Down
32 changes: 29 additions & 3 deletions src/HyperFormula.ts
Original file line number Diff line number Diff line change
Expand Up @@ -596,7 +596,21 @@ export class HyperFormula implements TypedEmitter {
}

/**
* Returns translated names of all registered functions for a given language
* Returns translated names of all registered functions for a given language.
*
* Answers for the function REGISTRY, so it cannot take a license key into account: it has no
* engine, and therefore no key, in scope. A restricted key makes the answer wrong for every
* purpose a caller usually has — a function picker built from this list offers functions that
* then evaluate to a `#LIC!` error. Use the instance method
* [[getRegisteredFunctionNames]] instead, which answers for the engine you actually hold.
*
* The two are not interchangeable: this one translates into any registered language without
* building an engine, while the instance method answers only under its own instance's language
* and license. Migrating means building an engine:
* `HyperFormula.buildEmpty({ language: 'plPL' }).getRegisteredFunctionNames()`.
*
* @deprecated Use the instance method of the same name. This static method is deprecated and
* will be removed in one of the next major releases.
*
* @param {string} code - language code
*
Expand Down Expand Up @@ -4549,6 +4563,17 @@ export class HyperFormula implements TypedEmitter {
* Returns translated names of all functions registered in this instance of HyperFormula
* according to the language set in the configuration
*
* Lists exactly what this instance can evaluate: the instance's listable ids (the protected
* built-ins included, uniformly), under the translation package its own evaluator uses, minus any
* function the instance's license key does not include — so a function picker built from these
* names never offers a function that then evaluates to a `#LIC!` error. A missing, invalid, or
* expired key does not shorten the list.
*
* The ids and the license rule are [[getAvailableFunctions]]'s, but the NAMES are not: this
* method reports each function's translation as the language pack spells it, so a function
* translated to an empty string is listed as `''`, where [[getAvailableFunctions]] falls back to
* the canonical id. Use that method when you need a name to show a user.
*
* @example
* ```js
* const hfInstance = HyperFormula.buildEmpty();
Expand All @@ -4560,8 +4585,9 @@ export class HyperFormula implements TypedEmitter {
* @category Custom Functions
*/
public getRegisteredFunctionNames(): string[] {
const language = HyperFormula.getLanguage(this._config.language)
return language.getFunctionTranslations(this._functionRegistry.getRegisteredFunctionIds())
const listableFunctionIds = this._functionRegistry.getListableFunctionIds()
.filter((functionId) => HyperFormula.licenseListsFunction(functionId, this._functionRegistry, this._config))
return this._config.translationPackage.getFunctionTranslations(listableFunctionIds)
}

/**
Expand Down
4 changes: 0 additions & 4 deletions src/interpreter/FunctionRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -285,10 +285,6 @@ export class FunctionRegistry {
return Array.from(plugins)
}

public getRegisteredFunctionIds(): string[] {
return Array.from(this.functions.keys())
}

public doesFunctionNeedArgumentToBeComputed = (functionId: string): boolean => this.functionsWhichDoesNotNeedArgumentsToBeComputed.has(functionId)

public isFunctionVolatile = (functionId: string): boolean => this.volatileFunctions.has(functionId)
Expand Down
Loading