formula-calc is a library for formula calculation through strings for javascript/typescript.
Note: The internal numerical calculation uses the decimal.js library.
npm install --save formula-calc
or
yarn add formula-calc
- basic
import formulaCalc from 'formula-calc';
const result = formulaCalc('1 + 1');
console.log(result); // 2
const result = formulaCalc('1 - 1');
console.log(result); // 0
const result = formulaCalc('2 * 3');
console.log(result); // 6
const result = formulaCalc('4 / 2');
console.log(result); // 2
const result = formulaCalc('5 ^ 2');
console.log(result); // 25
const result = formulaCalc('5 % 2')
console.log(result); // 1
const result = formulaCalc('2% + 1')
console.log(result); // 1.02
// with parenthesis
const result = formulaCalc('4 * (1 + 1) + 2')
console.log(result); // 10
- with variable
import formulaCalc, { createFormula } from 'formula-calc';
const result = formulaCalc('a + b.c', {
params: {
a: 1,
b: {
c: 2
}
}
});
console.log(result); // 3
const result = formulaCalc('a + b.c.1', {
params: {
a: 1,
b: {
c: [1, 2, 3]
}
}
});
console.log(result); // 3
// calc with params list
const result = formulaCalc('a + 1', {
params: [
{ a: 1 },
{ a: 2 },
{ a: 3 },
]
});
console.log(result); // [2, 3, 4]
// calc with formula instance
const formula = createFormula('a + 1');
const result = formulaCalc(formula, {
params: {
a: 1
}
});
console.log(result); // 2
// with promise
const result = await formulaCalc('a + 1', {
params: {
a: Promise.resolve(2),
}
});
console.log(result); // 3
- with function, built in functions: add, avg, ceil, eval, exist, floor, if, max, min, noref, random, round, sqrt, sum, trunc
import formulaCalc from 'formula-calc';
const result = formulaCalc('max(1, 2, 3, 4, 5)');
console.log(result); // 5
const result = formulaCalc('min(1, 2, 3, 4, 5)');
console.log(result); // 1
const result = formulaCalc('abs(-1)');
console.log(result); // 1
const result = formulaCalc('sum(1, 2, 3, 4, 5)');
console.log(result); // 15
const result = formulaCalc('sum(1, 2, 3, 4, a)', {
params: {
a: [5, 6, 7, 8]
}
});
console.log(result); // 36
const result = formulaCalc('round(2.335)');
console.log(result); // 2.34
const result = formulaCalc('round(2.335, 1)');
console.log(result); // 2.3
const result = formulaCalc('if(a, 1, 2)', {
params: {
a: true
}
});
console.log(result); // 1
const result = formulaCalc('if(a, 1, 2)', {
params: {
a: false
}
});
console.log(result); // 2
// with ref: like regex, $1...$n will match the ordinal of parentheses that do not contain functions
const result = formulaCalc(
`if(
(a + 2) > 0,
$1,
0 - $1
)`, {
params: {
a: -3
}
});
console.log(result); // 1
- with ref: like regex, $1...$n will match the ordinal of parentheses that do not contain functions
const result = formulaCalc(
`if(
(a + 2) > 0,
$1,
0 - $1
)`, {
params: {
a: -3
}
});
console.log(result); // 1
- with custom function
import formulaCalc from 'formula-calc';
const result = formulaCalc('add1(2.11)', {
customFunctions: {
add1: {
argMin: 1,
argMax: 1,
execute(params) {
return params[0] + 1;
}
}
}
});
console.log(result); // 3.11
- with eval
import formulaCalc from 'formula-calc';
const result = formulaCalc(
`if(
a > 0,
eval(planA),
eval(planB)
)`, {
params: {
a: -3,
planA: 'a + 1',
planB: '0 - a + 1',
}
});
console.log(result); // 4
- handle precision
import formulaCalc from 'formula-calc';
const result = formulaCalc('10 / 3');
console.log(result); // 3.3333333333333
const result = formulaCalc('10 / 3', { precision: 2 });
console.log(result); // 3.33
- rounding at each step of the operation
import formulaCalc from 'formula-calc';
const result = formulaCalc('3.334 + 3.335', {
stepPrecision: true,
});
console.log(result); // 6.67
const result = formulaCalc('3.3334 + 3.3315', {
precision: 2,
stepPrecision: 3,
};
console.log(result); // 6.67
- null as zero
import formulaCalc from 'formula-calc';
const result = formulaCalc('a.b.c', {
params: {
a: {}
}
});
console.log(result); // 0
- formulaCalc
type RoundingType = 'UP'|'DOWN'|'CEIL'|'FLOOR'|'HALF_UP'|'HALF_DOWN'|'HALF_EVEN'|'HALF_CEIL'|'HALF_FLOOR'|'EUCLID';
type FormulaValueOptions = {
Decimal?: typeof Decimal,
precision?: number,
rounding?: RoundingType,
stepPrecision?: boolean|number,
nullAsZero?: boolean,
cache?: boolean,
eval?: null|((expr: string, dataSource: IFormulaDataSource, options: FormulaValueOptions) => any),
}
interface FormulaOptions extends FormulaValueOptions {
}
interface FormulaCalcOptions extends FormulaOptions {
params?: Record<string, any>|((name: string) => any),
customFunctions?: Record<string, FormulaCustomFunctionItem>,
dataSource?: IFormulaDataSource,
}
declare function formulaCalc(
expression: string,
options: FormulaCalcOptions = {}
): any;
Supports the following values
-
number
- number, like 1, 2, 3, 1e3, 1e+3, 1e-3 -
string
- string, it is quoted with"
, like "1", "2", "3" -
boolean
- boolean, like true, false -
null
- null -
NaN
- NaN -
Infinity
- Infinity -
params
- params, likea
,a.b
,a.b.0
, "params" is taken from the "params" parameter in the second parameter of theformulaCalc
method. If theparam
name contains special characters, it can be quoted with'
, like this:'a()*_(&_&*)b'
-
ref
-$1
...$99
, similar to regular expressions, it will match the ordinal of parentheses that do not contain functions
Supports the following operators
-
+
- add -
-
- subtract -
*
- multiply -
/
- divide -
^
- power -
%
- mod -
=
- equal -
!=
- not equal -
>
- greater than -
>=
- greater than or equal to -
<
- less than -
<=
- less than or equal to -
&
- and -
|
- or -
!
- not -
()
- parenthesis
Supports the following built in functions:
-
abs(x)
- absolute value -
avg(n1, n2, ..., n99)
- average, note :nX
can be number array. -
ceil(x)
- ceiling -
eval(expr)
- evaluate expression -
exist(o, key, type?)
- check if the key exists in the object, if type is not specified, it will be checked for all types, if type is specified, it will be checked for the specified type. -
floor(x)
- floor -
if(a, b, c?)
- ifa
is true, then returnb
, otherwise returnc
-
max(n1, n2, ..., n99)
- maximum, note :nX
can be number array. -
min(n1, n2, ..., n99)
- minimum, note :nX
can be number array. -
noref(x)
- directly return x, becauseref
does not count the parentheses of a function, the parentheses wrapped innoref
will not be included in theref
. -
round(x, y?)
- round -
sqrt(x)
- square root -
sum(n1, n2, ..., n99)
- sum, note :nX
can be number array. -
random(n)
- random number -
trunc(x)
- truncate
Custom functions can be used to extend the formula language. due to the formula supporting promise calculation, you can even provide UI related interactions in custom methods
import formulaCalc from 'formula-calc';
const result = await formulaCalc('confirm("some prompt", 1, 2) + 1', {
customFunctions: {
confirm: {
argMin: 3,
argMax: 3,
execute([prompt, a, b]) {
return new Promise((resolve) => {
// some UI interaction
setTimeout(() => {
resolve(a > b ? a : b);
}, 1000);
});
}
}
}
});