Skip to content

Commit 46f8ce2

Browse files
committed
Initial commit
0 parents  commit 46f8ce2

9 files changed

+5706
-0
lines changed

.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
coverage/
2+
dist/
3+
node_modules/
4+
yarn-error.log

.vscode/settings.json

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"cSpell.words": [
3+
"BODMAS",
4+
"beyondessential",
5+
"unaries",
6+
"unary"
7+
]
8+
}

README.md

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# @beyondessential/arithmetic
2+
3+
Utility to evaluate [BODMAS](https://en.wikipedia.org/wiki/Order_of_operations) arithmetic formulas
4+
5+
### Installation
6+
7+
**Note:** Since this is a private repository, you will need to authenticate your connection to GitHub, for example via [ssh](https://docs.github.com/en/github/authenticating-to-github/connecting-to-github-with-ssh).
8+
9+
```
10+
yarn add beyondessential/arithmetic
11+
```
12+
13+
### Usage
14+
15+
```js
16+
import { runArithmetic } from '@beyondessential/arithmetic';
17+
18+
runArithmetic('(1 + 2) / 3');
19+
```

__tests__/arithmetic.test.js

+137
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
import { runArithmetic } from '../src/arithmetic';
2+
3+
describe('Arithmetic', () => {
4+
describe('basics', () => {
5+
it('should perform an addition', () => {
6+
const result = runArithmetic('1 + 2');
7+
expect(result).toEqual(1 + 2);
8+
});
9+
10+
it('should perform a subtraction', () => {
11+
const result = runArithmetic('1 - 2');
12+
expect(result).toEqual(1 - 2);
13+
});
14+
15+
it('should handle double digits', () => {
16+
const result = runArithmetic('10 - 20');
17+
expect(result).toEqual(10 - 20);
18+
});
19+
20+
it('should handle parentheses', () => {
21+
const result = runArithmetic('(4 + (1 + 2) + (2 + 5) + 1)');
22+
expect(result).toEqual(4 + (1 + 2) + (2 + 5) + 1);
23+
});
24+
});
25+
26+
describe('decimals', () => {
27+
it('should handle adding decimals', () => {
28+
const result = runArithmetic('5.5 - 1.9');
29+
expect(result).toEqual(5.5 - 1.9);
30+
});
31+
32+
it('should handle multiplying decimals', () => {
33+
const result = runArithmetic('2.5352 * 102.99');
34+
expect(result).toEqual(2.5352 * 102.99);
35+
});
36+
});
37+
38+
describe('multiplication', () => {
39+
it('should handle a simple multiplication', () => {
40+
const result = runArithmetic('5 * 3');
41+
expect(result).toEqual(5 * 3);
42+
});
43+
44+
it('should handle a bunch of operations', () => {
45+
const result = runArithmetic('(4 + (1 * 2) / (2 + 5) - 1)');
46+
expect(result).toEqual(4 + (1 * 2) / (2 + 5) - 1);
47+
});
48+
49+
it('should handle putting x instead of *', () => {
50+
const result = runArithmetic('5 x 3');
51+
expect(result).toEqual(5 * 3);
52+
});
53+
54+
it('should handle putting x in a more complicated expression', () => {
55+
const result = runArithmetic('(4 + (1 x 2) / (2 + 5) - 1)');
56+
expect(result).toEqual(4 + (1 * 2) / (2 + 5) - 1);
57+
});
58+
});
59+
60+
describe('unary minus (for eg, -1)', () => {
61+
it('should handle multiplying by a negative', () => {
62+
const result = runArithmetic('4 / - 2');
63+
expect(result).toEqual(4 / -2);
64+
});
65+
66+
it('should handle multiple negatives', () => {
67+
const result = runArithmetic('4 * - 2 * - 2');
68+
expect(result).toEqual(4 * -2 * -2);
69+
});
70+
71+
it('should handle multiplying by a double negative', () => {
72+
const result = runArithmetic('4 / - - 2');
73+
expect(result).toEqual(4 / 2);
74+
});
75+
76+
it('should handle negating a parenthesized expression', () => {
77+
const result = runArithmetic('-(4 / 2)');
78+
expect(result).toEqual(-(4 / 2));
79+
});
80+
81+
it('should handle multiplying by a negative', () => {
82+
const result = runArithmetic('3 * -(4 / 2)');
83+
expect(result).toEqual(3 * -(4 / 2));
84+
});
85+
86+
it('should handle varying whitespace', () => {
87+
const result = runArithmetic('1+1 - - 5');
88+
expect(result).toEqual(1 + 1 - -5);
89+
});
90+
});
91+
92+
describe('substituting values', () => {
93+
const VALUES = {
94+
fingers: 10,
95+
eyes: 2,
96+
pi: 3.14159,
97+
sins: 7,
98+
negative: -5,
99+
};
100+
101+
it('should handle simple value substitution', () => {
102+
const result = runArithmetic('fingers + eyes', VALUES);
103+
expect(result).toEqual(10 + 2);
104+
});
105+
106+
it('should handle negative value substitution', () => {
107+
const result = runArithmetic('fingers + negative', VALUES);
108+
expect(result).toEqual(10 - 5);
109+
});
110+
111+
it('should handle a more complicated case', () => {
112+
const result = runArithmetic('-eyes * (sins - pi * 3) / negative + (sins + 1)', VALUES);
113+
expect(result).toEqual((-2 * (7 - 3.14159 * 3)) / -5 + (7 + 1));
114+
});
115+
});
116+
117+
describe('errors', () => {
118+
it('should fail on an unexpected token', () => {
119+
expect(() => runArithmetic('fail')).toThrow();
120+
expect(() => runArithmetic('1 + fail')).toThrow();
121+
expect(() => runArithmetic('4 + (1 * fail) / 2')).toThrow();
122+
});
123+
124+
it('should fail on an unmatched parenthesis', () => {
125+
expect(() => runArithmetic(')')).toThrow();
126+
expect(() => runArithmetic('4 * (1 + 2')).toThrow();
127+
expect(() => runArithmetic('4 * 1) + 2')).toThrow();
128+
expect(() => runArithmetic('4 * 1 + 2)')).toThrow();
129+
});
130+
131+
it('should fail if a substitution is not numeric', () => {
132+
expect(() => runArithmetic('check + 1', { check: 'check' })).toThrow();
133+
expect(() => runArithmetic('check + 1', { check: '+' })).toThrow();
134+
expect(() => runArithmetic('check + 1', { check: '' })).toThrow();
135+
});
136+
});
137+
});

index.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export function runArithmetic(formula: string): number;

package.json

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
{
2+
"name": "@beyondessential/arithmetic",
3+
"private": true,
4+
"version": "1.0.0",
5+
"description": "Utility to evaluate BODMAS arithmetic formulas",
6+
"main": "dist/index.js",
7+
"files": [
8+
"src",
9+
"index.d.ts"
10+
],
11+
"homepage": "https://github.com/beyondessential/arithmetic.git#readme",
12+
"repository": "[email protected]:beyondessential/arithmetic.git",
13+
"scripts": {
14+
"build": "babel src --out-dir dist --ignore 'src/__tests__/**'",
15+
"postinstall": "yarn build",
16+
"test": "NODE_ENV=test jest",
17+
"test:coverage": "yarn test --coverage",
18+
"test:watch": "yarn test --watch"
19+
},
20+
"keywords": [],
21+
"author": "Beyond Essential Systems Pty. Ltd.",
22+
"license": "AGPL-3.0-only",
23+
"devDependencies": {
24+
"@babel/cli": "^7.10.5",
25+
"@babel/core": "^7.11.1",
26+
"@babel/preset-env": "^7.11.0",
27+
"@beyondessential/eslint-config-beyondessential": "^2.5.0",
28+
"babel-jest": "^26.3.0",
29+
"eslint": "^7.7.0",
30+
"jest": "^26.4.0",
31+
"prettier": "^2.0.5"
32+
},
33+
"eslintConfig": {
34+
"extends": "@beyondessential/eslint-config-beyondessential",
35+
"overrides": [
36+
{
37+
"files": "**/__tests__/**",
38+
"env": {
39+
"jest": true
40+
}
41+
}
42+
]
43+
},
44+
"babel": {
45+
"presets": [
46+
[
47+
"@babel/preset-env"
48+
]
49+
]
50+
}
51+
}

0 commit comments

Comments
 (0)