https://github.com/shuckster/eslint-plugin-big-number-rules
Enforce (or automatically fix) finance-safe calculations using BigNumber or similar libraries.
https://github.com/shuckster/eslint-plugin-big-number-rules
arithmetic bignumber eslint-plugin finance
Last synced: 5 months ago
JSON representation
Enforce (or automatically fix) finance-safe calculations using BigNumber or similar libraries.
- Host: GitHub
- URL: https://github.com/shuckster/eslint-plugin-big-number-rules
- Owner: shuckster
- License: mit
- Created: 2021-04-24T02:59:04.000Z (about 5 years ago)
- Default Branch: master
- Last Pushed: 2024-04-24T09:29:43.000Z (about 2 years ago)
- Last Synced: 2025-07-01T04:03:20.514Z (12 months ago)
- Topics: arithmetic, bignumber, eslint-plugin, finance
- Language: JavaScript
- Homepage:
- Size: 10.8 MB
- Stars: 16
- Watchers: 3
- Forks: 3
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
eslint-plugin-big-number-rules ๐ข
โ Enforce ๐ฐ _finance-safe_ ๐งท calculations using [bignumber.js](https://github.com/MikeMcl/bignumber.js/) (or something [similar](#customisation)!) instead of native JavaScript arithmetic and Math functions.

- [Customisable!](https://github.com/shuckster/eslint-plugin-big-number-rules/wiki/Customisation)
- [Noisy!](https://github.com/shuckster/eslint-plugin-big-number-rules/wiki/Limit-the-number-of-warnings)
- [Finance-safe?](#but-why)
```sh
$ pnpm i eslint-plugin-big-number-rules --save-dev
```
## Configuration
After installation, make the plugin available to your `eslint`:
```json
// .eslintrc
{
"plugins": ["big-number-rules"]
}
```
Recommended rules will `warn` about everything:
```json
// .eslintrc
{
"plugins": ["big-number-rules"],
"extends": ["plugin:big-number-rules/recommended"]
}
```
"Everything" means this:
```json
// .eslintrc
{
"plugins": ["big-number-rules"],
"rules": {
"big-number-rules/arithmetic": "warn",
"big-number-rules/assignment": "warn",
"big-number-rules/bitwise": "warn",
"big-number-rules/comparison": "warn",
"big-number-rules/isNaN": "warn",
"big-number-rules/math": "warn",
"big-number-rules/number": "warn",
"big-number-rules/parseFloat": "warn",
"big-number-rules/rounding": "warn"
},
"settings": {
"big-number-rules": {
// Specify the following if you want rules to
// apply only to files with this declaration:
//
// import ... from 'bignumber.js'
//
"importDeclaration": "bignumber.js",
// Optionally, you can also apply rules only when
// importing the desired specifier from such
// declarations:
//
// import BigNumber from 'bignumber.js'
//
"importSpecifier": "BigNumber",
// Optionally, you can disable suggestions for
// one or more infix operators using the following
// setting:
//
"unsafelyIgnoreSuggestionsForOperators": []
//
// Example:
//
// "unsafelyIgnoreSuggestionsForOperators": ["+", "+="]
}
}
}
```
You can also [customise](https://github.com/shuckster/eslint-plugin-big-number-rules/wiki/Customisation) the transformations.
# Example transforms:
| from | to | plugin will also suggest |
| -------------------------- | ------------------------------------ | ----------------------------------------------------------------------------------------------------------------- |
| `0.1 + 0.2` | `BigNumber.sum(0.1, 0.2)` | `('').concat(0.1, 0.2)` and `` `${0.1}${0.2}` `` when you want string-concatenation instead of financial arithmetic |
| `result === 0.3` | `BigNumber(result).isEqualTo(0.3)` | `Object.is(result, 0.3)` when you want to strictly compare things that are not financial calculations |
| `19.99 * 0.1` | `BigNumber(19.99).multipliedBy(0.1)` |
| `1 < 2` | `BigNumber(1).isLessThan(2)` |
| `2 >>> 4` | `BigNumber(2).shiftedBy(4)` |
| `4 << 2` | `BigNumber(4).shiftedBy(-2)` |
| `Math.min(1, 2)` | `BigNumber.minimum(1, 2)` |
| `Math.sign(-6)` | `BigNumber(-6).comparedTo(0)` |
| `(1).toFixed(2)` | `BigNumber(1).toFixed(2)` |
| `parseFloat('1.2')` | `BigNumber('1.2')` |
| `Number.parseFloat('2.1')` | `BigNumber('2.1')` |
Can keep a chain going...
```js
BigNumber.sum(0.1, 0.2) - 0.3
// --> BigNumber.sum(0.1, 0.2).minus(0.3)
3 ** BigNumber(1).plus(2)
// --> BigNumber(3).exponentiatedBy(BigNumber(1).plus(2))
```
# But why?
If you use floating-points for currency (instead of whole-numbers like you probably should) libraries like [bignumber.js](https://github.com/MikeMcl/bignumber.js/) help keep your code away from the binary floating-point [pitfalls](https://medium.com/@magnusjt/how-to-handle-money-in-javascript-b954d612373c) of [IEEE-754](https://stackoverflow.com/questions/3730019/why-not-use-double-or-float-to-represent-currency):
```js
const sum = 0.1 + 0.2
sum === 0.3
// false
sum
// 0.30000000000000004
```
This is the classic example and is often cited, but there are other rare corner-cases that will eventually be caught some time after committing to a currency-unsafe solution.
`eslint-plugin-big-number-rules` will translate the example above to:
```js
const sum = BigNumber.sum(0.1, 0.2)
BigNumber(sum).isEqualTo(0.3)
// true
```
The problem manifests in the first place because in the floating-point number-type of most languages (not just JavaScript!) the mantissa/significand is represented as a power-of-two fraction rather than a power-of-10 decimal:
```
_ _._____._____._____._____._____._____._____.______.______.__ _ _
_ _| 8 | 4 | 2 | 1 | 1/2 | 1/4 | 1/8 | 1/16 | 1/32 | ... etc
\__________.___________/ \______________________________ _ _ _
Exponent ------^ |
|
Significand ------>-------->----------^
```
IEEE-754 defines various rules for marshalling these fractions into a decimal, but as you can probably imagine it's not always exact.
Libraries like `bignumber.js` helps us work around this. Using them isn't complicated, but it does require a little discipline and vigilance to keep on top of, so an [eslint](https://eslint.org/) plugin to warn-about the use of JavaScript's native-math methods seemed like a good way to do that.
## But I use `+` for string-concatenation!
Since `v2.0.0` the plugin will now offer `String#concat()` and `Template String` replacements for `+` related rules, in addition to the default BigNumber suggestion:
```js
0.1 + 0.2
// -> BigNumber.sum(0.1, 0.2)
// -> ('').concat(0.1, 0.2)
// -> `${0.1}${0.2}`
result += 0.3
// -> result = BigNumber(result).plus(0.3)
// -> result = ('').concat(result, 0.3)
// -> result = `${result}${0.3}`
```
It will also offer `Object.is()` as a suggestion for `===` related rules:
```js
0.1 === 0.2
// -> BigNumber(0.1).isEqualTo(0.2)
// -> Object.is(0.1, 0.2)
0.1 !== 0.2
// -> !BigNumber(0.1).isEqualTo(0.2)
// -> !Object.is(0.1, 0.2)
```
## I want to take the risk of ignoring certain infix operators!
Since `v2.1.0` you can use the `unsafelyIgnoreSuggestionsForOperators` option to ignore one or more suggestions for the infix operators:
```json
// .eslintrc
{
"plugins": ["big-number-rules"],
"settings": {
"big-number-rules": {
"unsafelyIgnoreSuggestionsForOperators": ["+", "+="]
}
}
}
```
> ๐ **Note:** Since `v2.2.0` I hope you will be less inclined to use this setting because detection of concat operations on string-literals [is improved](https://github.com/shuckster/eslint-plugin-big-number-rules/blob/master/CHANGELOG.md#220---2023-04-12).
# Credits
`eslint-plugin-big-number-rules` was written by [Conan Theobald](https://github.com/shuckster/).
He was inspired by the work of these fine Internet folk:
- [bignumber.js](https://github.com/MikeMcl/bignumber.js/) :)
- [eslint-plugin-bignumber](https://github.com/fnando/eslint-plugin-bignumber)
- [eslint-plugin-arithmetic](https://github.com/JonnyBurger/eslint-plugin-arithmetic)
- [AST Explorer](https://astexplorer.net/)
๐
## Contributing
If you'd like to offer a material contribution, I like [coffee โ๏ธ](https://www.buymeacoffee.com/shuckster) :)
# License
MIT licensed: See [LICENSE](LICENSE)