Skip to content
Merged
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

- Added a new function: IRR. [#1591](https://github.com/handsontable/hyperformula/issues/1591)
- Added a new function: N. [#1585](https://github.com/handsontable/hyperformula/issues/1585)
- Added a new function: VALUE. [#1592](https://github.com/handsontable/hyperformula/issues/1592)

## [3.1.1] - 2025-12-18

Expand Down
1 change: 1 addition & 0 deletions docs/guide/built-in-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,7 @@ Total number of functions: **{{ $page.functionsCount }}**
| UNICHAR | Returns the character created by using provided code point. | UNICHAR(Number) |
| UNICODE | Returns the Unicode code point of a first character of a text. | UNICODE(Text) |
| UPPER | Returns text converted to uppercase. | UPPER(Text) |
| VALUE | Parses a number, date, time, datetime, currency, or percentage from a text string. | VALUE(Text) |

[^non-odff]:
The return value of this function is compliant with the
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
"test": "npm-run-all lint test:unit test:browser test:compatibility",
"test:unit": "cross-env NODE_ICU_DATA=node_modules/full-icu jest",
"test:watch": "cross-env NODE_ICU_DATA=node_modules/full-icu jest --watch",
"test:tdd": "cross-env NODE_ICU_DATA=node_modules/full-icu jest --watch adding-sheet",
"test:tdd": "cross-env NODE_ICU_DATA=node_modules/full-icu jest --watch function-value",
"test:coverage": "npm run test:unit -- --coverage",
"test:logMemory": "cross-env NODE_ICU_DATA=node_modules/full-icu jest --runInBand --logHeapUsage",
"test:unit.ci": "cross-env NODE_ICU_DATA=node_modules/full-icu node --expose-gc ./node_modules/jest/bin/jest --forceExit",
Expand Down
2 changes: 1 addition & 1 deletion src/NumberLiteralHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export class NumberLiteralHelper {
const thousandSeparator = this.config.thousandSeparator === '.' ? `\\${this.config.thousandSeparator}` : this.config.thousandSeparator
const decimalSeparator = this.config.decimalSeparator === '.' ? `\\${this.config.decimalSeparator}` : this.config.decimalSeparator

this.numberPattern = new RegExp(`^([+-]?((${decimalSeparator}\\d+)|(\\d+(${thousandSeparator}\\d{3,})*(${decimalSeparator}\\d*)?)))(e[+-]?\\d+)?$`)
this.numberPattern = new RegExp(`^([+-]?((${decimalSeparator}\\d+)|(\\d+(${thousandSeparator}\\d{3,})*(${decimalSeparator}\\d*)?)))([eE][+-]?\\d+)?$`)
this.allThousandSeparatorsRegex = new RegExp(`${thousandSeparator}`, 'g')
}

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 @@ -225,6 +225,7 @@ const dictionary: RawTranslationPackage = {
UNICHAR: 'UNICHAR',
UNICODE: 'UNICODE',
UPPER: 'VELKÁ',
VALUE: 'HODNOTA',
VARA: 'VARA',
'VAR.P': 'VAR.P',
VARPA: 'VARPA',
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 @@ -225,6 +225,7 @@ const dictionary: RawTranslationPackage = {
UNICHAR: 'UNICHAR',
UNICODE: 'UNICODE',
UPPER: 'STORE.BOGSTAVER',
VALUE: 'VÆRDI',
VARA: 'VARIANSV',
'VAR.P': 'VARIANS.P',
VARPA: 'VARIANSPV',
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 @@ -225,6 +225,7 @@ const dictionary: RawTranslationPackage = {
UNICHAR: 'UNIZEICHEN',
UNICODE: 'UNICODE',
UPPER: 'GROSS',
VALUE: 'WERT',
VARA: 'VARIANZA',
'VAR.P': 'VAR.P',
VARPA: 'VARIANZENA',
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 @@ -227,6 +227,7 @@ const dictionary: RawTranslationPackage = {
UNICHAR: 'UNICHAR',
UNICODE: 'UNICODE',
UPPER: 'UPPER',
VALUE: 'VALUE',
VARA: 'VARA',
'VAR.P': 'VAR.P',
VARPA: 'VARPA',
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 @@ -225,6 +225,7 @@ export const dictionary: RawTranslationPackage = {
UNICHAR: 'UNICHAR',
UNICODE: 'UNICODE',
UPPER: 'MAYUSC',
VALUE: 'VALOR',
VARA: 'VARA',
'VAR.P': 'VAR.P',
VARPA: 'VARPA',
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 @@ -225,6 +225,7 @@ const dictionary: RawTranslationPackage = {
UNICHAR: 'UNICODEMERKKI',
UNICODE: 'UNICODE',
UPPER: 'ISOT',
VALUE: 'ARVO',
VARA: 'VARA',
'VAR.P': 'VAR.P',
VARPA: 'VARPA',
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 @@ -225,6 +225,7 @@ const dictionary: RawTranslationPackage = {
UNICHAR: 'UNICAR',
UNICODE: 'UNICODE',
UPPER: 'MAJUSCULE',
VALUE: 'CNUM',
VARA: 'VARA',
'VAR.P': 'VAR.P.N',
VARPA: 'VARPA',
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 @@ -225,6 +225,7 @@ const dictionary: RawTranslationPackage = {
UNICHAR: 'UNIKARAKTER',
UNICODE: 'UNICODE',
UPPER: 'NAGYBETŰS',
VALUE: 'ÉRTÉK',
VARA: 'VARA',
'VAR.P': 'VAR.S',
VARPA: 'VARPA',
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 @@ -225,6 +225,7 @@ const dictionary: RawTranslationPackage = {
UNICHAR: 'CARATT.UNI',
UNICODE: 'UNICODE',
UPPER: 'MAIUSC',
VALUE: 'VALORE',
VARA: 'VAR.VALORI',
'VAR.P': 'VAR.P',
VARPA: 'VAR.POP.VALORI',
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 @@ -225,6 +225,7 @@ const dictionary: RawTranslationPackage = {
UNICHAR: 'UNICODETEGN',
UNICODE: 'UNICODE',
UPPER: 'STORE',
VALUE: 'VERDI',
VARA: 'VARIANSA',
'VAR.P': 'VARIANS.P',
VARPA: 'VARIANSPA',
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 @@ -225,6 +225,7 @@ const dictionary: RawTranslationPackage = {
UNICHAR: 'UNITEKEN',
UNICODE: 'UNICODE',
UPPER: 'HOOFDLETTERS',
VALUE: 'WAARDE',
VARA: 'VARA',
'VAR.P': 'VAR.P',
VARPA: 'VARPA',
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 @@ -225,6 +225,7 @@ const dictionary: RawTranslationPackage = {
UNICHAR: 'ZNAK.UNICODE',
UNICODE: 'UNICODE',
UPPER: 'LITERY.WIELKIE',
VALUE: 'WARTOŚĆ',
VARA: 'WARIANCJA.A',
'VAR.P': 'WARIANCJA.POP',
VARPA: 'WARIANCJA.POPUL.A',
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 @@ -225,6 +225,7 @@ const dictionary: RawTranslationPackage = {
UNICHAR: 'CARACTUNI',
UNICODE: 'UNICODE',
UPPER: 'MAIÚSCULA',
VALUE: 'VALOR',
VARA: 'VARA',
'VAR.P': 'VAR.P',
VARPA: 'VARPA',
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 @@ -225,6 +225,7 @@ const dictionary: RawTranslationPackage = {
UNICHAR: 'ЮНИСИМВ',
UNICODE: 'UNICODE',
UPPER: 'ПРОПИСН',
VALUE: 'ЗНАЧ',
VARA: 'ДИСПА',
'VAR.P': 'ДИСП.Г',
VARPA: 'ДИСПРА',
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 @@ -225,6 +225,7 @@ const dictionary: RawTranslationPackage = {
UNICHAR: 'UNICHAR',
UNICODE: 'UNICODE',
UPPER: 'VERSALER',
VALUE: 'TEXTNUM',
VARA: 'VARA',
'VAR.P': 'VARIANS.P',
VARPA: 'VARPA',
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 @@ -225,6 +225,7 @@ const dictionary: RawTranslationPackage = {
UNICHAR: 'UNICODEKARAKTERİ',
UNICODE: 'UNICODE',
UPPER: 'BÜYÜKHARF',
VALUE: 'DEĞER',
VARA: 'VARA',
'VAR.P': 'VAR.P',
VARPA: 'VARSA',
Expand Down
74 changes: 69 additions & 5 deletions src/interpreter/plugin/TextPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@

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

/**
Expand Down Expand Up @@ -149,15 +150,21 @@ export class TextPlugin extends FunctionPlugin implements FunctionPluginTypechec
{argumentType: FunctionArgumentType.STRING}
]
},
'VALUE': {
method: 'value',
parameters: [
{argumentType: FunctionArgumentType.SCALAR}
]
},
}

/**
* Corresponds to CONCATENATE(value1, [value2, ...])
*
* Concatenates provided arguments to one string.
*
* @param ast
* @param state
* @param {ProcedureAst} ast - The procedure AST node
* @param {InterpreterState} state - The interpreter state
*/
public concatenate(ast: ProcedureAst, state: InterpreterState): InterpreterValue {
return this.runFunction(ast.args, state, this.metadata('CONCATENATE'), (...args) => {
Expand All @@ -170,8 +177,8 @@ export class TextPlugin extends FunctionPlugin implements FunctionPluginTypechec
*
* Splits provided string using space separator and returns chunk at zero-based position specified by second argument
*
* @param ast
* @param state
* @param {ProcedureAst} ast - The procedure AST node
* @param {InterpreterState} state - The interpreter state
*/
public split(ast: ProcedureAst, state: InterpreterState): InterpreterValue {
return this.runFunction(ast.args, state, this.metadata('SPLIT'), (stringToSplit: string, indexToUse: number) => {
Expand Down Expand Up @@ -376,6 +383,63 @@ export class TextPlugin extends FunctionPlugin implements FunctionPluginTypechec
})
}

/**
* Corresponds to VALUE(text)
*
* Converts a text string that represents a number to a number.
*
* @param {ProcedureAst} ast - The procedure AST node
* @param {InterpreterState} state - The interpreter state
*/
public value(ast: ProcedureAst, state: InterpreterState): InterpreterValue {
return this.runFunction(ast.args, state, this.metadata('VALUE'), (arg: RawScalarValue): ExtendedNumber | CellError => {
if (arg instanceof CellError) {
return arg
}

if (isExtendedNumber(arg)) {
return arg
}

if (typeof arg !== 'string') {
return new CellError(ErrorType.VALUE, ErrorMessage.NumberCoercion)
}

const trimmedArg = arg.trim()

const parenthesesMatch = /^\(([^()]+)\)$/.exec(trimmedArg)
if (parenthesesMatch) {
const innerValue = this.parseStringToNumber(parenthesesMatch[1])
if (innerValue !== undefined) {
return -innerValue
}
}

const parsedValue = this.parseStringToNumber(trimmedArg)
if (parsedValue !== undefined) {
return parsedValue
}

return new CellError(ErrorType.VALUE, ErrorMessage.NumberCoercion)
})
}

/**
* Parses a string to a numeric value, handling whitespace trimming and empty string validation.
*
* @param {string} input - The string to parse
* @returns {Maybe<ExtendedNumber>} The parsed number or undefined if parsing fails or input is empty
*/
private parseStringToNumber(input: string): Maybe<ExtendedNumber> {
const trimmedInput = input.trim()

if (trimmedInput === '') {
return undefined
}

return this.arithmeticHelper.coerceToMaybeNumber(trimmedInput)
}

private escapeRegExpSpecialCharacters(text: string): string {
return text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
}
Expand Down
Loading
Loading