exprify 1.0.4 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/HISTORY.md ADDED
@@ -0,0 +1,49 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on Keep a Changelog, and this project follows semantic versioning.
6
+
7
+ ## [1.0.5] - 2026-06-12
8
+
9
+ ### Added
10
+
11
+ - ESLint (v10 flat config) with strict rules, Prettier formatting, and TypeScript JSDoc type checking
12
+ - Husky pre-commit hook with lint-staged for automatic linting and formatting on commit
13
+ - Dependabot config for weekly automated dependency pull requests
14
+ - CodeQL security analysis workflow on push/PR/schedule
15
+ - Bundle size monitoring via size-limit (min.js: 30 KB, esm.js: 60 KB)
16
+ - Jest coverage reporting (`npm run test:coverage`) with CI artifact upload
17
+ - Node.js 24 to CI test matrix (previously 20 and 22 only)
18
+ - `.editorconfig` for cross-editor consistency
19
+ - `// @ts-check` annotations to all 14 source files
20
+ - `engines` field requiring Node >=18
21
+
22
+ ### Changed
23
+
24
+ - Upgraded Rollup from v2 to v4 with updated plugin versions
25
+ - Replaced rimraf with built-in `fs.rmSync` for the clean script
26
+ - Replaced nodemon with Node.js built-in `--watch` flag for the dev script
27
+ - CI workflow now runs lint, typecheck, size check, and coverage in addition to tests
28
+ - Switched CI workflows to Node 24 for publish and audit jobs
29
+ - Added `--no-warnings` flag to test scripts to suppress ExperimentalWarning
30
+
31
+ ### Fixed
32
+
33
+ - All ESLint errors (no-unused-vars, no-undef, eqeqeq, prefer-const, camelcase, etc.)
34
+ - All TypeScript type errors (err unknown type, null checks, variable store reference)
35
+ - lint-staged Windows ENOENT error by switching from package.json config to `lint-staged.config.js` with direct `node` invocation
36
+
37
+ ### Removed
38
+
39
+ - Unused Babel dependencies (@babel/cli, @babel/core, @babel/preset-env)
40
+ - Unused rollup-plugin-strip-banner, glob, and rimraf dev dependencies
41
+ - `overrides` section (test-exclude, glob pins) — no longer needed with Jest 30
42
+ - `nodemon` devDependency (replaced by `node --watch`)
43
+
44
+ ## [1.0.1] - 2026-04-05
45
+
46
+ ### Fixed
47
+
48
+ - Corrected the import path in `src/index.js` to match the actual filename casing of `src/core/Exprify.js`.
49
+ - Resolved a cross-platform build issue where Rollup failed on Linux-based CI environments because of case-sensitive path resolution.
package/README.md CHANGED
@@ -1,8 +1,32 @@
1
- # Exprify
1
+ [![Version](https://img.shields.io/npm/v/exprify)](https://www.npmjs.com/package/exprify)
2
+ [![Downloads](https://img.shields.io/npm/dt/exprify)](https://www.npmjs.com/package/exprify)
3
+ [![License](https://img.shields.io/github/license/code-hemu/exprify)](https://github.com/code-hemu/exprify/blob/master/LICENSE)
4
+ [![jsDelivr](https://data.jsdelivr.com/v1/package/npm/exprify/badge?style=rounded)](https://www.jsdelivr.com/package/npm/exprify)
5
+ [![unpkg](https://img.shields.io/badge/CDN-unpkg-blue)](https://unpkg.com/exprify)
6
+ [![Issues](https://img.shields.io/github/issues/code-hemu/exprify)](https://github.com/code-hemu/exprify/issues)
7
+ [![Contributors](https://img.shields.io/github/contributors/code-hemu/exprify)](https://github.com/code-hemu/exprify/graphs/contributors)
8
+ [![Sponsor](https://img.shields.io/github/sponsors/code-hemu)](https://github.com/sponsors/code-hemu)
2
9
 
3
- [![Exprify Social Banner](https://raw.githubusercontent.com/code-hemu/Exprify/refs/heads/main/docs/assets/capture.jpg)](https://github.com/code-hemu/Exprify)
10
+ [![Exprify Banner](https://raw.githubusercontent.com/code-hemu/Exprify/refs/heads/main/docs/assets/capture.jpg)](https://github.com/code-hemu/Exprify)
4
11
 
5
- Exprify is a JavaScript expression parser and evaluator for math-heavy apps. It supports arithmetic, variables, custom functions, unit conversion, matrices, complex numbers, symbolic helpers, and a growing set of linear algebra utilities.
12
+ **Exprify** (**Math Expr**ession + Simp**lify**) parses a string into an expression tree, evaluates it with a given set of variables, and lets you chain or compose operations together - in the browser and in Node.js.
13
+
14
+ ## Features
15
+
16
+ | Capability | Example | Docs |
17
+ |---|---|---|
18
+ | **Arithmetic & Variables** | `expr.evaluate("5 + 7 * 2")` | [datatypes/numbers.md](docs/datatypes/numbers.md) |
19
+ | **Unit conversion** | `expr.evaluate("2 inch to cm")` | [datatypes/units.md](docs/datatypes/units.md) |
20
+ | **Matrix operations** | `expr.evaluate("det([-1,2;3,1])")` | [datatypes/matrices.md](docs/datatypes/matrices.md) |
21
+ | **Complex numbers** | `expr.evaluate("9/3 + 2i")` | [datatypes/complex.md](docs/datatypes/complex_numbers.md) |
22
+ | **Symbolic math** | `expr.evaluate('expand("(x+1)^2")')` | [expressions/algebra.md](docs/expressions/algebra.md) |
23
+ | **Arbitrary precision** | `expr.evaluate('bignumber("0.1") + bignumber("0.2")')` | [datatypes/bignumbers.md](docs/datatypes/bignumbers.md) |
24
+ | **Exact fractions** | `expr.evaluate("fraction(1,3) + fraction(1,6)")` | [datatypes/fractions.md](docs/datatypes/fractions.md) |
25
+ | **Calculus & statistics** | `expr.evaluate('integral("x^2", 0, 1)')` | [reference/functions.md](docs/reference/functions.md) |
26
+ | **Lambda expressions** | `expr.evaluate('map([1,2,3], x -> x^2)')` | [expressions/customization.md](docs/expressions/customization.md) |
27
+ | **Expression chaining** | `c.evaluate("sqrt(x)").evaluate("ans * 2").done()` | [core/chaining.md](docs/core/chaining.md) |
28
+ | **State serialization** | `expr.exportState()` / `expr.importState(state)` | [core/serialization.md](docs/core/serialization.md) |
29
+ | **Degree-mode trig** | `expr.evaluate("sind(90)")` | [reference/functions.md](docs/reference/functions.md) |
6
30
 
7
31
  ## Installation
8
32
 
@@ -12,270 +36,172 @@ npm install exprify
12
36
 
13
37
  ## Quick Start
14
38
 
15
- **ESM** (Node.js, bundlers):
39
+ **ESM** (Node.js / bundlers):
16
40
 
17
41
  ```js
18
42
  import Exprify from "exprify";
19
43
 
20
44
  const expr = new Exprify();
21
45
 
22
- console.log(expr.evaluate("5 + 7 * 2"));
23
- // 19
46
+ expr.evaluate("5 + 7 * 2"); // 19
24
47
 
25
48
  expr.setVariable("x", 10);
26
- console.log(expr.evaluate("x + 5"));
27
- // 15
49
+ expr.evaluate("x + 5"); // 15
28
50
  ```
29
51
 
30
- **CommonJS** (`require`):
52
+ **CommonJS:**
31
53
 
32
54
  ```js
33
55
  const Exprify = require("exprify");
34
56
 
35
57
  const expr = new Exprify();
36
- console.log(expr.evaluate("5 + 7 * 2"));
37
- // 19
58
+ expr.evaluate("5 + 7 * 2"); // 19
38
59
  ```
39
60
 
40
- ## Browser Usage
61
+ **Browser (CDN):**
41
62
 
42
63
  ```html
43
64
  <script src="https://unpkg.com/exprify"></script>
44
65
  <script>
45
66
  const expr = new Exprify();
46
- console.log(expr.evaluate("(10 + 5) * 2"));
67
+ expr.evaluate("(10 + 5) * 2"); // 30
47
68
  </script>
48
69
  ```
49
70
 
50
- `unpkg` resolves to the browser bundle from `dist/exprify.min.js`.
51
-
52
71
  ## Module Formats
53
72
 
54
- The package ships a separate build for each consumer, and `package.json`'s `exports` field routes each import style to the right file:
73
+ `package.json`'s `exports` field routes each import style to the correct build automatically.
55
74
 
56
75
  | Consumer | Resolved file | Notes |
57
- | --- | --- | --- |
58
- | `import Exprify from "exprify"` (ESM) | `dist/exprify.esm.js` | Default export is the `Exprify` class. |
59
- | `const Exprify = require("exprify")` (CJS) | `dist/exprify.cjs.cjs` | `module.exports` is the `Exprify` class. |
60
- | `<script src="https://unpkg.com/exprify">` | `dist/exprify.min.js` | UMD build; exposes `Exprify` as a global. |
61
- | `import "exprify/dist/exprify.js"` (UMD) | `dist/exprify.js` | Unminified UMD for bundlers that prefer it. |
76
+ |---|---|---|
77
+ | `import Exprify from "exprify"` | `dist/exprify.esm.js` | Default export is the `Exprify` class |
78
+ | `require("exprify")` | `dist/exprify.cjs.cjs` | `module.exports` is the `Exprify` class |
79
+ | `<script src="https://unpkg.com/exprify">` | `dist/exprify.min.js` | UMD build; exposes `Exprify` as a global |
80
+ | `import "exprify/dist/exprify.js"` | `dist/exprify.js` | Unminified UMD for bundlers that prefer it |
62
81
 
63
- The `.cjs` extension on the CommonJS bundle keeps it loadable as CJS even though the package is `"type": "module"`, so `require()` and `import` both work without configuration.
82
+ > The `.cjs` extension keeps the CommonJS bundle loadable via `require()` even though the package uses `"type": "module"`.
64
83
 
65
84
  ## API
66
85
 
67
86
  ### `new Exprify()`
68
87
 
69
- Creates a new evaluator instance with isolated state for:
88
+ Creates a new evaluator instance with isolated state for variables, functions, units, and a compiled-expression cache.
70
89
 
71
- - variables
72
- - functions
73
- - units
74
- - compiled-expression cache
90
+ ### `expr.evaluate(expression, scope?)`
75
91
 
76
- ### `expr.evaluate(expression)`
77
-
78
- Parses and evaluates an expression string.
92
+ Parses and evaluates an expression string. An optional `scope` object overrides variables for that single call only.
79
93
 
80
94
  ```js
81
- expr.evaluate("10 + 5 * 2");
82
- // 20
95
+ expr.evaluate("10 + 5 * 2"); // 20
96
+
97
+ expr.setVariable("x", 100);
98
+ expr.evaluate("x + 1", { x: 5 }); // 6
83
99
  ```
84
100
 
85
101
  ### `expr.parse(expression)`
86
102
 
87
- Returns `{ tokens, ast }`.
103
+ Returns `{ tokens, ast }` - the raw token list and abstract syntax tree.
88
104
 
89
105
  ```js
90
- const parsed = expr.parse("2 inch to cm");
91
- console.log(parsed.tokens);
92
- console.log(parsed.ast);
106
+ const { tokens, ast } = expr.parse("2 inch to cm");
93
107
  ```
94
108
 
95
109
  ### `expr.compile(expression)`
96
110
 
97
- Compiles an expression once and returns a reusable function.
111
+ Compiles an expression once and returns a reusable function - ideal for hot paths.
98
112
 
99
113
  ```js
100
114
  const area = expr.compile("width * height");
101
-
102
- console.log(area({ width: 6, height: 4 }));
103
- // 24
115
+ area({ width: 6, height: 4 }); // 24
116
+ area({ width: 3, height: 9 }); // 27
104
117
  ```
105
118
 
106
119
  ### `expr.setVariable(name, value)` / `expr.getVariable(name)`
107
120
 
108
- Stores and reuses values across evaluations.
121
+ Stores and retrieves named values that persist across evaluations.
109
122
 
110
123
  ```js
111
124
  expr.setVariable("x", 10);
112
125
  expr.setVariable("y", 5);
113
-
114
- console.log(expr.evaluate("x + y * 2"));
115
- // 20
126
+ expr.evaluate("x + y * 2"); // 20
116
127
  ```
117
128
 
118
129
  ### `expr.addFunction(name, fn)`
119
130
 
120
- Registers a custom JavaScript function.
131
+ Registers a custom JavaScript function, making it callable inside expressions.
121
132
 
122
133
  ```js
123
134
  expr.addFunction("double", (n) => n * 2);
124
-
125
- console.log(expr.evaluate("double(5) + 3"));
126
- // 13
127
- ```
128
-
129
- ### Inline Function Definitions
130
-
131
- You can define functions inside expressions.
132
-
133
- ```js
134
- expr.evaluate("hyp(a, b) = sqrt(a ^ 2 + b ^ 2)");
135
-
136
- console.log(expr.evaluate("hyp(3, 4)"));
137
- // 5
135
+ expr.evaluate("double(5) + 3"); // 13
138
136
  ```
139
137
 
140
- ## Features
141
-
142
- ### Arithmetic
143
-
144
- ```js
145
- expr.evaluate("2 + 3 * 4");
146
- // 14
147
-
148
- expr.evaluate("(2 + 3) * 4");
149
- // 20
150
-
151
- expr.evaluate("11n ^ 2n");
152
- // 121n
153
- ```
138
+ ### `expr.chain()`
154
139
 
155
- ### Strings, Booleans, Complex Numbers
140
+ Returns a fluent `Chain` object. Each step stores its result as `ans` for the next expression.
156
141
 
157
142
  ```js
158
- expr.evaluate('"Hello " + "World"');
159
- // "Hello World"
160
-
161
- expr.evaluate("true && false");
162
- // false
163
-
164
- expr.evaluate("9 / 3 + 2i");
165
- // "3 + 2i"
166
- ```
167
-
168
- ### Unit Conversion
169
-
170
- ```js
171
- expr.evaluate("2 inch to cm");
172
- // "5.08 cm"
173
-
174
- expr.evaluate("5 cm + 2 inch");
175
- // "10.08 cm"
176
-
177
- expr.evaluate("5cm + 0.2 m in inch");
178
- // "9.84251968503937 inch"
179
-
180
- expr.evaluate("a = 5.08 cm + 2 inch");
181
- expr.evaluate("a to inch");
182
- // "4 inch"
143
+ const c = expr.chain();
144
+ c.setVariable("x", 25);
145
+ c.evaluate("sqrt(x) + 3"); // ans = 8
146
+ c.evaluate("ans * 2"); // ans = 16
147
+ c.done(); // 16
183
148
  ```
184
149
 
185
- ### Matrices
150
+ ### `expr.exportState()` / `expr.importState(state)`
186
151
 
187
- Exprify supports matrix literals with `;` as row separators.
152
+ Serializes and restores the full engine state - variables, functions, and units.
188
153
 
189
154
  ```js
190
- expr.evaluate("a = [1, 2, 3; 4, 5, 6]");
191
- // {"exprify":"DenseMatrix","data":[[1,2,3],[4,5,6]],"size":[2,3]}
192
-
193
- expr.evaluate("a[2, 3]");
194
- // 6
195
-
196
- expr.evaluate("a[1:2, 2]");
197
- // "2\n5"
155
+ const state = expr.exportState();
156
+ // { variables: {...}, functions: [...], units: {...} }
198
157
 
199
- expr.evaluate("a[3, 1:3] = [7, 8, 9]");
200
- // "7\t8\t9"
201
-
202
- expr.evaluate("det([-1, 2; 3, 1])");
203
- // -7
158
+ const expr2 = new Exprify();
159
+ expr2.importState(state);
204
160
  ```
205
161
 
206
- ### Linear Algebra Helpers
207
-
208
- ```js
209
- expr.evaluate("lup([[2, 1], [1, 4]])");
210
- // {"L":{"exprify":"DenseMatrix",...},"U":{"exprify":"DenseMatrix",...},"p":[0,1]}
211
-
212
- expr.evaluate("lyap([[-2, 0], [1, -4]], [[3, 1], [1, 3]])");
213
- // {"exprify":"DenseMatrix","data":[[0.75,0.2916666666666667],[0.2916666666666667,0.44791666666666663]],"size":[2,2]}
214
-
215
- expr.evaluate("qr([[1, -1, 4], [1, 4, -2], [1, 4, 2], [1, -1, 0]])");
216
- // {"Q":{"exprify":"DenseMatrix",...},"R":{"exprify":"DenseMatrix",...}}
217
-
218
- expr.evaluate("polynomialRoot(-6, 11, -6, 1)");
219
- // [1,3,2]
220
- ```
221
-
222
- Available helpers currently include `det`, `lsolve`, `lup`, `lyap`, `qr`, and `polynomialRoot`.
223
-
224
- ### Algebra Helpers
225
-
226
- ```js
227
- expr.evaluate('simplify("2x + x")');
228
- // "3 * x"
229
-
230
- expr.evaluate('derivative("2x^2 + 3x + 4", "x")');
231
- // "4 * x + 3"
232
-
233
- expr.evaluate('rationalize("2x/y - y/(x+1)", true)');
234
- // {"numerator":"2 * x ^ 2 + 2 * x - y ^ 2","denominator":"x * y + y","coefficients":[],"variables":["x","y"],"expression":"(2 * x ^ 2 + 2 * x - y ^ 2) / (x * y + y)"}
235
- ```
162
+ ### Inline Function Definitions
236
163
 
237
- ### Parse and AST Utilities
164
+ Functions can be defined directly inside expressions and reused immediately.
238
165
 
239
166
  ```js
240
- expr.evaluate('leafCount("e^(i*pi)-1")');
241
- // 4
242
-
243
- expr.evaluate('leafCount(parse("{a: 22/7, b: 10^(1/2)}"))');
244
- // 5
167
+ expr.evaluate("hyp(a, b) = sqrt(a^2 + b^2)");
168
+ expr.evaluate("hyp(3, 4)"); // 5
245
169
  ```
246
170
 
247
- ### Built-in Functions
171
+ ## Built-in Functions (Selected)
248
172
 
249
- Common built-ins include:
173
+ | Function | Description | Example | Result |
174
+ |---|---|---|---|
175
+ | `abs` | Absolute value | `abs(-5)` | `5` |
176
+ | `round` | Round to nearest integer | `round(3.7)` | `4` |
177
+ | `floor` | Round down | `floor(3.7)` | `3` |
178
+ | `ceil` | Round up | `ceil(3.2)` | `4` |
250
179
 
251
- - `max`, `min`, `abs`, `round`, `floor`, `ceil`, `sqrt`, `pow`
252
- - `sin`, `cos`, `tan`, `asin`, `acos`, `atan`
253
- - `log`, `log10`, `exp`, `random`
254
- - `clamp`, `if`, `length`, `typeof`
255
- - `det`, `lsolve`, `lup`, `lyap`, `qr`, `polynomialRoot`
256
- - `simplify`, `derivative`, `rationalize`, `leafCount`, `parse`
180
+ > See the [full searchable function reference](docs/reference/functions.md) for all ~130 built-in functions.
257
181
 
258
182
  ## Return Types
259
183
 
260
- Depending on the expression, `evaluate()` may return:
261
-
262
- - numbers / bigint / booleans
263
- - strings
264
- - formatted unit strings like `"5.08 cm"`
265
- - formatted complex strings like `"3 + 2i"`
266
- - matrix wrapper JSON strings such as `{"exprify":"DenseMatrix",...}`
267
- - JSON strings for structured helper outputs like `lup()` or `rationalize(..., true)`
184
+ | Type | Example expression | Result |
185
+ |---|---|---|
186
+ | Number / BigInt / Boolean | `2 + 2`, `true && false` | `4`, `false` |
187
+ | String | `"hello" + " world"` | `"hello world"` |
188
+ | Unit string | `2 inch to cm` | `"5.08 cm"` |
189
+ | Complex string | `3 + 2i` | `"3 + 2i"` |
190
+ | Matrix JSON | `[1,2;3,4]` | `{"exprify":"DenseMatrix",...}` |
191
+ | Structured JSON | `lup(...)`, `rationalize(..., true)` | JSON object string |
192
+ | Function | `x -> x^2` | Native JS function |
193
+ | Array | `1:5` | `[1,2,3,4,5]` |
268
194
 
269
195
  ## Manual Build
270
196
 
271
197
  ```bash
272
- git clone https://github.com/code-hemu/Exprify.git
198
+ git clone https://github.com/code-hemu/exprify.git
273
199
  cd Exprify
274
200
  npm install
275
201
  npm run build
276
202
  ```
277
203
 
278
- Build output is written to `dist/`.
204
+ Output is written to `dist/`.
279
205
 
280
206
  ## Testing
281
207
 
@@ -283,21 +209,15 @@ Build output is written to `dist/`.
283
209
  npm test
284
210
  ```
285
211
 
286
- Tested in CI across Node 20 and 22 (see `.github/workflows/ci.yml`).
287
-
288
- ## Publishing
289
-
290
- The package is published to the public npm registry via `npm publish`. The `npm-publish.yml` workflow runs on GitHub release events. See `.github/workflows/npm-publish.yml` for details.
291
-
292
- `package-lock.json` is committed but is not shipped in the published tarball (see `.npmignore`); consumers generate their own lockfile when installing.
293
-
294
- ## License
295
-
296
- Exprify is licensed under GPL-3.0. Copyright (c) [Nirmal Paul](https://github.com/nirmalpaul383/).
212
+ Tested in CI across Node 20 and 22. See `.github/workflows/ci.yml` for details.
297
213
 
298
214
  ## Contributing
299
215
 
300
216
  1. Fork the repository.
301
217
  2. Create a branch: `git checkout -b feature/your-feature`
302
218
  3. Commit your changes: `git commit -m "Add your feature"`
303
- 4. Push your branch and open a pull request.
219
+ 4. Push and open a pull request.
220
+
221
+ ## License
222
+
223
+ Exprify is licensed under **GPL-3.0**. Copyright © [Nirmal Paul](https://github.com/nirmalpaul383/).
package/SECURITY.md ADDED
@@ -0,0 +1,18 @@
1
+ # Security Policy
2
+
3
+ ## Supported Versions
4
+
5
+ | Version | Supported |
6
+ | ------- | --------- |
7
+ | 1.0.5 | ❌ |
8
+ | 1.0.6 | ✅ |
9
+
10
+ ## Reporting a Vulnerability
11
+
12
+ If you discover a security vulnerability in Exprify, please report it privately by opening a security advisory at:
13
+
14
+ https://github.com/code-hemu/exprify/security/advisories/new
15
+
16
+ You can expect an acknowledgment within 48 hours and a detailed response within 5 business days. If the vulnerability is accepted, a fix will be coordinated through a private release and published as a patch version. If declined, you will receive an explanation of why the issue does not constitute a security risk.
17
+
18
+ Please do **not** report security vulnerabilities through public GitHub issues, discussions, or pull requests.