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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
### Added

- Added support for the new license key format. A proprietary key can now grant a subset of the library: a function your key does not include evaluates to a `#LIC!` error, and the matching parts of the API throw a `LicenseCapabilityMissingError`. `getAvailableFunctions()` and `getFunctionDetails()` describe only the functions your key includes. [#1728](https://github.com/handsontable/hyperformula/pull/1728)
- Added a new function: `GESTEP`. [#1788](https://github.com/handsontable/hyperformula/pull/1788)

### Changed

Expand All @@ -19,6 +20,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
### Fixed

- Fixed the validation of classic (25-character) license keys depending on the time zone: east of UTC, a key that expired the day before the build was released was still accepted, and west of UTC, the console message printed an expiry date one day too early. [#1728](https://github.com/handsontable/hyperformula/pull/1728)
- Fixed the `DELTA` function returning a number for a boolean or an empty text argument instead of `#VALUE!` as Excel does; numeric text, dates and empty cells are still accepted. [#1788](https://github.com/handsontable/hyperformula/pull/1788)
- Fixed number literals with an uppercase exponent marker, such as `=1E5` or `=1E-3`, being rejected as a parse error; the lowercase form was already accepted. [#1788](https://github.com/handsontable/hyperformula/pull/1788)
- Fixed the `AVERAGEIF` function returning a division-by-zero error when the calculated average was `0`. [#1733](https://github.com/handsontable/hyperformula/pull/1733)
- Fixed the localized names of `VSTACK` and `HSTACK` in 14 language packs to match Microsoft Excel. [#1748](https://github.com/handsontable/hyperformula/pull/1748)
- Fixed the MAXPOOL and MEDIANPOOL functions throwing an uncaught `TypeError` instead of returning the `#VALUE!` error when the range dimensions are not a whole multiple of the window size and the stride. [#1718](https://github.com/handsontable/hyperformula/pull/1718)
Expand Down
1 change: 1 addition & 0 deletions src/i18n/languages/csCZ.ts
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@ const dictionary: RawTranslationPackage = {
'CONFIDENCE.T': 'CONFIDENCE.T',
DEVSQ: 'DEVSQ',
GEOMEAN: 'GEOMEAN',
GESTEP: 'GESTEP',
HARMEAN: 'HARMEAN',
CRITBINOM: 'CRITBINOM',
PEARSON: 'PEARSON',
Expand Down
1 change: 1 addition & 0 deletions src/i18n/languages/daDK.ts
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@ const dictionary: RawTranslationPackage = {
'CONFIDENCE.T': 'KONFIDENST',
DEVSQ: 'SAK',
GEOMEAN: 'GEOMIDDELV脝RDI',
GESTEP: 'GESTEP',
HARMEAN: 'HARMIDDELV脝RDI',
CRITBINOM: 'KRITBINOM',
PEARSON: 'PEARSON',
Expand Down
1 change: 1 addition & 0 deletions src/i18n/languages/deDE.ts
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@ const dictionary: RawTranslationPackage = {
'CONFIDENCE.T': 'KONFIDENZ.T',
DEVSQ: 'SUMQUADABW',
GEOMEAN: 'GEOMITTEL',
GESTEP: 'GESTEP',
HARMEAN: 'HARMITTEL',
CRITBINOM: 'KRITBINOM',
PEARSON: 'PEARSON',
Expand Down
1 change: 1 addition & 0 deletions src/i18n/languages/enGB.ts
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@ const dictionary: RawTranslationPackage = {
'CONFIDENCE.T': 'CONFIDENCE.T',
DEVSQ: 'DEVSQ',
GEOMEAN: 'GEOMEAN',
GESTEP: 'GESTEP',
HARMEAN: 'HARMEAN',
CRITBINOM: 'CRITBINOM',
'COVARIANCE.P': 'COVARIANCE.P',
Expand Down
1 change: 1 addition & 0 deletions src/i18n/languages/esES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@ export const dictionary: RawTranslationPackage = {
'CONFIDENCE.T': 'INTERVALO.CONFIANZA.T',
DEVSQ: 'DESVIA2',
GEOMEAN: 'MEDIA.GEOM',
GESTEP: 'GESTEP',
HARMEAN: 'MEDIA.ARMO',
CRITBINOM: 'BINOM.CRIT',
PEARSON: 'PEARSON',
Expand Down
1 change: 1 addition & 0 deletions src/i18n/languages/fiFI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@ const dictionary: RawTranslationPackage = {
'CONFIDENCE.T': 'LUOTTAMUSV脛LI.T',
DEVSQ: 'OIKAISTU.NELI脰SUMMA',
GEOMEAN: 'KESKIARVO.GEOM',
GESTEP: 'GESTEP',
HARMEAN: 'KESKIARVO.HARM',
CRITBINOM: 'BINOMIJAKAUMA.KRIT',
PEARSON: 'PEARSON',
Expand Down
1 change: 1 addition & 0 deletions src/i18n/languages/frFR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@ const dictionary: RawTranslationPackage = {
'CONFIDENCE.T': 'INTERVALLE.CONFIANCE.STUDENT',
DEVSQ: 'SOMME.CARRES.ECARTS',
GEOMEAN: 'MOYENNE.GEOMETRIQUE',
GESTEP: 'GESTEP',
HARMEAN: 'MOYENNE.HARMONIQUE',
CRITBINOM: 'CRITERE.LOI.BINOMIALE',
PEARSON: 'PEARSON',
Expand Down
1 change: 1 addition & 0 deletions src/i18n/languages/huHU.ts
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@ const dictionary: RawTranslationPackage = {
'CONFIDENCE.T': 'MEGB脥ZHAT脫S脕G.T',
DEVSQ: 'SQ',
GEOMEAN: 'M脡RTANI.K脰Z脡P',
GESTEP: 'GESTEP',
HARMEAN: 'HARM.K脰Z脡P',
CRITBINOM: 'KRITBINOM',
PEARSON: 'PEARSON',
Expand Down
1 change: 1 addition & 0 deletions src/i18n/languages/idID.ts
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@ const dictionary: RawTranslationPackage = {
'CONFIDENCE.T': 'KEYAKINAN.T',
DEVSQ: 'KUADRAT.SIMPANG',
GEOMEAN: 'RATA.GEO',
GESTEP: 'GESTEP',
HARMEAN: 'RATA.HARM',
CRITBINOM: 'KRIT.BINOM',
'COVARIANCE.P': 'KOVAR.P',
Expand Down
1 change: 1 addition & 0 deletions src/i18n/languages/itIT.ts
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@ const dictionary: RawTranslationPackage = {
'CONFIDENCE.T': 'CONFIDENZA.T',
DEVSQ: 'DEV.Q',
GEOMEAN: 'MEDIA.GEOMETRICA',
GESTEP: 'GESTEP',
HARMEAN: 'MEDIA.ARMONICA',
CRITBINOM: 'CRIT.BINOM',
PEARSON: 'PEARSON',
Expand Down
1 change: 1 addition & 0 deletions src/i18n/languages/nbNO.ts
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@ const dictionary: RawTranslationPackage = {
'CONFIDENCE.T': 'KONFIDENS.T',
DEVSQ: 'AVVIK.KVADRERT',
GEOMEAN: 'GJENNOMSNITT.GEOMETRISK',
GESTEP: 'GESTEP',
HARMEAN: 'GJENNOMSNITT.HARMONISK',
CRITBINOM: 'GRENSE.BINOM',
PEARSON: 'PEARSON',
Expand Down
1 change: 1 addition & 0 deletions src/i18n/languages/nlNL.ts
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@ const dictionary: RawTranslationPackage = {
'CONFIDENCE.T': 'VERTROUWELIJKHEID.T',
DEVSQ: 'DEV.KWAD',
GEOMEAN: 'MEETK.GEM',
GESTEP: 'GESTEP',
HARMEAN: 'HARM.GEM',
CRITBINOM: 'CRIT.BINOM',
PEARSON: 'PEARSON',
Expand Down
1 change: 1 addition & 0 deletions src/i18n/languages/plPL.ts
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@ const dictionary: RawTranslationPackage = {
'CONFIDENCE.T': 'UFNO艢膯.T',
DEVSQ: 'ODCH.KWADRATOWE',
GEOMEAN: '艢REDNIA.GEOMETRYCZNA',
GESTEP: 'GESTEP',
HARMEAN: '艢REDNIA.HARMONICZNA',
CRITBINOM: 'PR脫G.ROZK艁AD.DWUM',
PEARSON: 'PEARSON',
Expand Down
1 change: 1 addition & 0 deletions src/i18n/languages/ptPT.ts
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@ const dictionary: RawTranslationPackage = {
'CONFIDENCE.T': 'INT.CONFIAN脟A.T',
DEVSQ: 'DESVQ',
GEOMEAN: 'M脡DIA.GEOM脡TRICA',
GESTEP: 'GESTEP',
HARMEAN: 'M脡DIA.HARM脭NICA',
CRITBINOM: 'CRIT.BINOM',
PEARSON: 'PEARSON',
Expand Down
1 change: 1 addition & 0 deletions src/i18n/languages/ruRU.ts
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@ const dictionary: RawTranslationPackage = {
'CONFIDENCE.T': '袛袨袙袝袪袠孝.小孝鞋挟袛袝袧孝',
DEVSQ: '袣袙袗袛袪袨孝袣袥',
GEOMEAN: '小袪袚袝袨袦',
GESTEP: 'GESTEP',
HARMEAN: '小袪袚袗袪袦',
CRITBINOM: '袣袪袠孝袘袠袧袨袦',
PEARSON: 'PEARSON',
Expand Down
1 change: 1 addition & 0 deletions src/i18n/languages/svSE.ts
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@ const dictionary: RawTranslationPackage = {
'CONFIDENCE.T': 'KONFIDENS.T',
DEVSQ: 'KVADAVV',
GEOMEAN: 'GEOMEDEL',
GESTEP: 'GESTEP',
HARMEAN: 'HARMMEDEL',
CRITBINOM: 'KRITBINOM',
PEARSON: 'PEARSON',
Expand Down
1 change: 1 addition & 0 deletions src/i18n/languages/trTR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@ const dictionary: RawTranslationPackage = {
'CONFIDENCE.T': 'G脺VEN陌L陌RL陌K.T',
DEVSQ: 'SAPKARE',
GEOMEAN: 'GEOORT',
GESTEP: 'GESTEP',
HARMEAN: 'HARORT',
CRITBINOM: 'KR陌T陌KB陌NOM',
PEARSON: 'PEARSON',
Expand Down
7 changes: 7 additions & 0 deletions src/interpreter/functionMetadata/categories/engineering.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,13 @@ export const ENGINEERING_DOCS: Record<string, FunctionDoc> = {
documentationUrl: 'https://hyperformula.handsontable.com/docs/guide/built-in-functions.html',
examples: ['=DELTA(5, 5)', '=DELTA(5, 4)', '=DELTA(0)'],
},
GESTEP: {
category: 'Engineering',
shortDescription: 'Returns 1 if number is greater than or equal to step, otherwise returns 0.',
parameters: [{name: 'number', description: 'The value to compare against the step.'}, {name: 'step', description: 'The threshold value; defaults to 0 when omitted.'}],
documentationUrl: 'https://hyperformula.handsontable.com/docs/guide/built-in-functions.html',
examples: ['=GESTEP(5, 4)', '=GESTEP(3, 4)', '=GESTEP(-1)'],
},
ERF: {
category: 'Engineering',
shortDescription: 'Returns values of the Gaussian error integral.',
Expand Down
99 changes: 72 additions & 27 deletions src/interpreter/plugin/DeltaPlugin.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,72 @@
/**
* @license
* Copyright (c) 2025 Handsoncode. All rights reserved.
*/

import {ProcedureAst} from '../../parser'
import {InterpreterState} from '../InterpreterState'
import {InterpreterValue} from '../InterpreterValue'
import {FunctionArgumentType, FunctionPlugin, FunctionPluginTypecheck, ImplementedFunctions} from './FunctionPlugin'

export class DeltaPlugin extends FunctionPlugin implements FunctionPluginTypecheck<DeltaPlugin> {
public static implementedFunctions: ImplementedFunctions = {
'DELTA': {
method: 'delta',
parameters: [
{argumentType: FunctionArgumentType.NUMBER},
{argumentType: FunctionArgumentType.NUMBER, defaultValue: 0},
]
},
}

public delta(ast: ProcedureAst, state: InterpreterState): InterpreterValue {
return this.runFunction(ast.args, state, this.metadata('DELTA'),
(left: number, right: number) => (left === right ? 1 : 0)
)
}
}
/**
* @license
* Copyright (c) 2025 Handsoncode. All rights reserved.
*/

import {CellError, ErrorType} from '../../Cell'
import {ErrorMessage} from '../../error-message'
import {ProcedureAst} from '../../parser'
import {InterpreterState} from '../InterpreterState'
import {getRawValue, InternalScalarValue, InterpreterValue} from '../InterpreterValue'
import {FunctionArgumentType, FunctionPlugin, FunctionPluginTypecheck, ImplementedFunctions} from './FunctionPlugin'

export class DeltaPlugin extends FunctionPlugin implements FunctionPluginTypecheck<DeltaPlugin> {
public static implementedFunctions: ImplementedFunctions = {
'DELTA': {
method: 'delta',
parameters: [
{argumentType: FunctionArgumentType.SCALAR},
{argumentType: FunctionArgumentType.SCALAR, defaultValue: 0},
]
},
'GESTEP': {
method: 'gestep',
parameters: [
{argumentType: FunctionArgumentType.SCALAR},
{argumentType: FunctionArgumentType.SCALAR, defaultValue: 0},
]
},
}

/**
* Converts an argument the way Excel does for these functions: numbers, dates, numeric text and empty cells are
* accepted, while a boolean or the empty text is #VALUE!. Errors are passed on. The second argument is checked first,
* as Excel does, so an error or a type error in it wins over one in the first argument.
*/
private strictNumber(value: InternalScalarValue): number | CellError {
if (value instanceof CellError) {
return value
}
if (typeof value === 'boolean' || value === '') {
return new CellError(ErrorType.VALUE, ErrorMessage.NumberCoercion)
}
const coerced = this.coerceScalarToNumberOrError(value)
return coerced instanceof CellError ? coerced : getRawValue(coerced)
}

public delta(ast: ProcedureAst, state: InterpreterState): InterpreterValue {
return this.runFunction(ast.args, state, this.metadata('DELTA'),
(left: InternalScalarValue, right: InternalScalarValue) => {
const b = this.strictNumber(right)
const a = this.strictNumber(left)
if (b instanceof CellError) {
return b
}
return a instanceof CellError ? a : (a === b ? 1 : 0)
}
)
}

public gestep(ast: ProcedureAst, state: InterpreterState): InterpreterValue {
return this.runFunction(ast.args, state, this.metadata('GESTEP'),
(num: InternalScalarValue, step: InternalScalarValue) => {
const b = this.strictNumber(step)
const a = this.strictNumber(num)
if (b instanceof CellError) {
return b
}
return a instanceof CellError ? a : (a >= b ? 1 : 0)
}
)
}
}
2 changes: 1 addition & 1 deletion src/license/functionCapabilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ const UNGROUPED_FUNCTIONS = [
'DOLLARFR', 'DPRODUCT', 'DSTDEV', 'DSTDEVP', 'DSUM', 'DVAR', 'DVARP', 'EFFECT', 'ERF', 'ERFC',
'EXPON.DIST', 'F.DIST', 'F.DIST.RT', 'F.INV', 'F.INV.RT', 'F.TEST', 'FACT', 'FACTDOUBLE', 'FISHER',
'FISHERINV', 'FLOOR.MATH', 'FLOOR.PRECISE', 'FORMULATEXT', 'FVSCHEDULE', 'GAMMA', 'GAMMA.DIST',
'GAMMA.INV', 'GAMMALN', 'GAUSS', 'GCD', 'GEOMEAN', 'HARMEAN', 'HEX2BIN', 'HEX2OCT', 'HYPGEOM.DIST',
'GAMMA.INV', 'GAMMALN', 'GAUSS', 'GCD', 'GEOMEAN', 'GESTEP', 'HARMEAN', 'HEX2BIN', 'HEX2OCT', 'HYPGEOM.DIST',
'IMABS', 'IMAGINARY', 'IMARGUMENT', 'IMCONJUGATE', 'IMCOS', 'IMCOSH', 'IMCOT', 'IMCSC', 'IMCSCH', 'IMDIV',
'IMEXP', 'IMLN', 'IMLOG10', 'IMLOG2', 'IMPOWER', 'IMPRODUCT', 'IMREAL', 'IMSEC', 'IMSECH', 'IMSIN',
'IMSINH', 'IMSQRT', 'IMSUB', 'IMSUM', 'IMTAN', 'INTERVAL', 'ISBINARY', 'ISFORMULA', 'ISNONTEXT', 'ISPMT',
Expand Down
2 changes: 1 addition & 1 deletion src/parser/LexerConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export const buildLexerConfig = (config: ParserConfig): LexerConfig => {
const WhiteSpace = createToken({ name: 'WhiteSpace', pattern: whitespaceTokenRegexp })
const ArrayRowSeparator = createToken({name: 'ArrayRowSep', pattern: config.arrayRowSeparator})
const ArrayColSeparator = createToken({name: 'ArrayColSep', pattern: config.arrayColumnSeparator})
const NumberLiteral = createToken({ name: 'NumberLiteral', pattern: new RegExp(`(([${config.decimalSeparator}]\\d+)|(\\d+([${config.decimalSeparator}]\\d*)?))(e[+-]?\\d+)?`) })
const NumberLiteral = createToken({ name: 'NumberLiteral', pattern: new RegExp(`(([${config.decimalSeparator}]\\d+)|(\\d+([${config.decimalSeparator}]\\d*)?))(e[+-]?\\d+)?`, 'i') })
const OffsetProcedureName = createToken({ name: 'OffsetProcedureName', pattern: new RegExp(offsetProcedureNameLiteral, 'i') })

let ArgSeparator: TokenType
Expand Down
Loading