-
Notifications
You must be signed in to change notification settings - Fork 18
/
Copy pathcalculator.ts
38 lines (35 loc) · 1.31 KB
/
calculator.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import { parseValueWithUnit, valueWithUnitRegExpGlobal } from "./units";
// Map lower case version of a Math proper to the qualified property (with
// proper case), e.g. abs => Math.abs, pi => Math.PI.
//
// All symbols except Math.E are supported. E unfornately appears in scientific
// notations all the time.
const supportedMathSymbols = new Map(
(Object.getOwnPropertyNames(Math)
.filter(symbol => symbol !== 'E')
.map(symbol => [symbol.toLowerCase(), `Math.${symbol}`]) as [string, string][]).concat(
// Additional supported aliases.
[
['ln', 'Math.log'],
['lg', 'Math.log10'],
]
)
);
const mathSymbolPattern = `\\b${[...supportedMathSymbols.keys()].join('|')}\\b`;
const mathSymbolRegExpGlobal = new RegExp(mathSymbolPattern, 'gi');
// Returns null on error.
export function calculateWithOoMUnits(expr: string): number | null {
expr = expr.replaceAll(valueWithUnitRegExpGlobal, value => parseValueWithUnit(value)!.toString());
expr = expr.replaceAll(
mathSymbolRegExpGlobal,
value => supportedMathSymbols.get(value.toLowerCase())!
);
// Interpret ^ as exponentiation, because who the hell cares about xor.
expr = expr.replaceAll(/\^/g, '**');
try {
const result = eval(expr);
return typeof result === 'number' ? result : null;
} catch (e) {
return null;
}
}