Skip to content

Commit dc8f482

Browse files
committed
Reduce codeduplication
1 parent 4dbda00 commit dc8f482

6 files changed

Lines changed: 27 additions & 61 deletions

File tree

docs/guide/built-in-functions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -506,7 +506,7 @@ Total number of functions: **{{ $page.functionsCount }}**
506506
| UNICHAR | Returns the character created by using provided code point. | UNICHAR(Number) |
507507
| UNICODE | Returns the Unicode code point of a first character of a text. | UNICODE(Text) |
508508
| UPPER | Returns text converted to uppercase. | UPPER(Text) |
509-
| VALUE | Converts a text string that represents a number to a number. | VALUE(Text) |
509+
| VALUE | Parses a number, date, time, datetime, currency, or percentage from a text string. | VALUE(Text) |
510510

511511
[^non-odff]:
512512
The return value of this function is compliant with the

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@
7878
"test": "npm-run-all lint test:unit test:browser test:compatibility",
7979
"test:unit": "cross-env NODE_ICU_DATA=node_modules/full-icu jest",
8080
"test:watch": "cross-env NODE_ICU_DATA=node_modules/full-icu jest --watch",
81-
"test:tdd": "cross-env NODE_ICU_DATA=node_modules/full-icu jest --watch adding-sheet",
81+
"test:tdd": "cross-env NODE_ICU_DATA=node_modules/full-icu jest --watch function-value",
8282
"test:coverage": "npm run test:unit -- --coverage",
8383
"test:logMemory": "cross-env NODE_ICU_DATA=node_modules/full-icu jest --runInBand --logHeapUsage",
8484
"test:unit.ci": "cross-env NODE_ICU_DATA=node_modules/full-icu node --expose-gc ./node_modules/jest/bin/jest --forceExit",

src/CellContentParser.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,8 @@ export class CellContentParser {
139139
} else {
140140
let trimmedContent = content.trim()
141141
let mode = 0
142-
let currency
143-
if (trimmedContent.endsWith('%')) {
142+
let currency // currency
143+
if (trimmedContent.endsWith('%')) { // percentage
144144
mode = 1
145145
trimmedContent = trimmedContent.slice(0, trimmedContent.length - 1)
146146
} else {

src/NumberLiteralHelper.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export class NumberLiteralHelper {
1616
const thousandSeparator = this.config.thousandSeparator === '.' ? `\\${this.config.thousandSeparator}` : this.config.thousandSeparator
1717
const decimalSeparator = this.config.decimalSeparator === '.' ? `\\${this.config.decimalSeparator}` : this.config.decimalSeparator
1818

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

src/interpreter/ArithmeticHelper.ts

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -222,41 +222,6 @@ export class ArithmeticHelper {
222222
)
223223
}
224224

225-
/**
226-
* Parses a string to a number, supporting percentages, currencies, numeric strings, and date/time formats.
227-
* Unlike coerceNonDateScalarToMaybeNumber, this also handles scientific notation with uppercase E.
228-
*/
229-
public parseStringToNumber(input: string): Maybe<ExtendedNumber> {
230-
const trimmedInput = input.trim()
231-
232-
// Try percentage
233-
const percentResult = this.coerceStringToMaybePercentNumber(trimmedInput)
234-
if (percentResult !== undefined) {
235-
return percentResult
236-
}
237-
238-
// Try currency
239-
const currencyResult = this.coerceStringToMaybeCurrencyNumber(trimmedInput)
240-
if (currencyResult !== undefined) {
241-
return currencyResult
242-
}
243-
244-
// Try plain number (normalize scientific notation E to e)
245-
const normalizedInput = trimmedInput.replace(/E/g, 'e')
246-
const numberResult = this.numberLiteralsHelper.numericStringToMaybeNumber(normalizedInput)
247-
if (numberResult !== undefined) {
248-
return numberResult
249-
}
250-
251-
// Try date/time
252-
const dateTimeResult = this.dateTimeHelper.dateStringToDateNumber(trimmedInput)
253-
if (dateTimeResult !== undefined) {
254-
return dateTimeResult
255-
}
256-
257-
return undefined
258-
}
259-
260225
public coerceNonDateScalarToMaybeNumber(arg: InternalScalarValue): Maybe<ExtendedNumber> {
261226
if (arg === EmptyValue) {
262227
return 0

src/interpreter/plugin/TextPlugin.ts

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import {CellError, ErrorType} from '../../Cell'
77
import {ErrorMessage} from '../../error-message'
8+
import { Maybe } from '../../Maybe'
89
import {ProcedureAst} from '../../parser'
910
import {InterpreterState} from '../InterpreterState'
1011
import {SimpleRangeValue} from '../../SimpleRangeValue'
@@ -400,39 +401,39 @@ export class TextPlugin extends FunctionPlugin implements FunctionPluginTypechec
400401
return arg
401402
}
402403

403-
if (typeof arg === 'boolean') {
404+
if (typeof arg !== 'string') {
404405
return new CellError(ErrorType.VALUE, ErrorMessage.NumberCoercion)
405406
}
406407

407-
if (typeof arg === 'string') {
408-
if (arg === '') {
409-
return new CellError(ErrorType.VALUE, ErrorMessage.NumberCoercion)
410-
}
411-
412-
const trimmedArg = arg.trim()
408+
const trimmedArg = arg.trim()
413409

414-
// Try parsing parentheses notation for negative numbers: "(123)" -> -123
415-
const parenthesesMatch = /^\(([^()]+)\)$/.exec(trimmedArg)
416-
if (parenthesesMatch) {
417-
const innerValue = this.arithmeticHelper.parseStringToNumber(parenthesesMatch[1])
418-
if (innerValue !== undefined) {
419-
return -innerValue
420-
}
421-
}
422-
423-
// Try standard parsing
424-
const parsedValue = this.arithmeticHelper.parseStringToNumber(trimmedArg)
425-
if (parsedValue !== undefined) {
426-
return parsedValue
410+
const parenthesesMatch = /^\(([^()]+)\)$/.exec(trimmedArg)
411+
if (parenthesesMatch) {
412+
const innerValue = this.parseStringToNumber(parenthesesMatch[1])
413+
if (innerValue !== undefined) {
414+
return -innerValue
427415
}
416+
}
428417

429-
return new CellError(ErrorType.VALUE, ErrorMessage.NumberCoercion)
418+
const parsedValue = this.parseStringToNumber(trimmedArg)
419+
if (parsedValue !== undefined) {
420+
return parsedValue
430421
}
431422

432423
return new CellError(ErrorType.VALUE, ErrorMessage.NumberCoercion)
433424
})
434425
}
435426

427+
private parseStringToNumber(input: string): Maybe<ExtendedNumber> {
428+
const trimmedInput = input.trim()
429+
430+
if (trimmedInput === '') {
431+
return undefined
432+
}
433+
434+
return this.arithmeticHelper.coerceToMaybeNumber(trimmedInput)
435+
}
436+
436437
private escapeRegExpSpecialCharacters(text: string): string {
437438
return text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
438439
}

0 commit comments

Comments
 (0)