Skip to content
Open
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

## [Unreleased]

### Added

- Added `DetailedCellError.hasMessage`, so a consumer can tell a cell error that never carried a message (e.g. a custom function that omitted one) apart from one with a deliberately empty message — both previously surfaced identically as `message: ''`. [#1547](https://github.com/handsontable/hyperformula/issues/1547)

### Changed

- Changed the cell errors thrown by the formula engine to always carry a message describing their cause. [#1547](https://github.com/handsontable/hyperformula/issues/1547)
Expand Down
6 changes: 6 additions & 0 deletions docs/guide/custom-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,12 @@ custom error messages. Put them to good use: let your users know what caused the
error and how to avoid it in the future.
:::

Every error the engine raises while evaluating a formula carries a message. A custom function's
`message` argument stays optional — if you omit it, a consumer reading the resulting
`DetailedCellError` sees `message` as an empty string, the same value HyperFormula uses
for "no message". To tell the two cases apart, check `hasMessage`: `true` means a
message was set (even if it's a deliberately empty string), `false` means none was.

### Test your function

To make sure your function works correctly, add unit tests. Use a JavaScript
Expand Down
13 changes: 13 additions & 0 deletions src/CellValue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,26 @@ export class DetailedCellError {
public readonly type: ErrorType
public readonly message: string

/**
* Whether the underlying error carried a message at all.
*
* `message` collapses "no message" and "an empty message" into `''`; this flag
* keeps them apart for consumers that need to know whether a cause was stated.
* Errors the engine raises while evaluating a formula always carry a message. A
* `false` here means nobody stated a cause: a custom function that did not supply
* one, or an error value a user typed straight into a cell, where the cause is the
* typing itself and `originFunction` says so.
*/
public readonly hasMessage: boolean

constructor(
error: CellError,
public readonly value: string,
public readonly address?: string,
) {
this.type = error.type
this.message = error.message ?? ''
this.hasMessage = error.message !== undefined
}

public toString(): string {
Expand Down
1 change: 1 addition & 0 deletions test/_setupFiles/matchers/cellErrorComparison.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const IGNORED_IN_STRUCTURAL_COMPARE = {
address: undefined,
originFunction: undefined,
argumentIndex: undefined,
hasMessage: undefined,
propagated: undefined,
originAddress: undefined,
originAddressVersion: undefined,
Expand Down
Loading