exprify 1.0.3 → 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 +49 -0
- package/README.md +113 -160
- package/SECURITY.md +18 -0
- package/bin/cli.mjs +234 -0
- package/dist/exprify.cjs.cjs +5341 -0
- package/dist/exprify.cjs.cjs.map +1 -0
- package/dist/exprify.esm.js +3558 -1220
- package/dist/exprify.esm.js.map +1 -1
- package/dist/exprify.js +3560 -1222
- package/dist/exprify.js.map +1 -1
- package/dist/exprify.min.js +2 -2
- package/dist/exprify.min.js.map +1 -1
- package/package.json +55 -19
- package/src/core/context.js +35 -27
- package/src/core/exprify.js +880 -0
- package/src/function/executor.js +29 -20
- package/src/function/internal.js +1150 -153
- package/src/function/registry.js +23 -16
- package/src/index.js +1 -1
- package/src/math/bignumber.js +31 -0
- package/src/math/fraction.js +112 -0
- package/src/math/operations.js +38 -24
- package/src/parser/astBuild.js +276 -214
- package/src/parser/evaluator.js +431 -171
- package/src/parser/tokenizer.js +179 -146
- package/src/utils/decimal.js +264 -0
- package/src/utils/globalUnits.js +43 -35
- package/src/utils/matrix.js +14 -14
- package/src/utils/store.js +69 -47
- package/src/variables/store.js +18 -15
- package/dist/exprify.cjs.js +0 -3003
- package/dist/exprify.cjs.js.map +0 -1
- package/src/assets/capture.jpg +0 -0
- package/src/core/Exprify.js +0 -369
package/src/utils/store.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
export function createUnitsStore(initial = {}) {
|
|
2
|
-
let units = { ...initial};
|
|
3
|
-
|
|
4
|
-
// ---------- Helpers ----------
|
|
2
|
+
let units = { ...initial };
|
|
5
3
|
|
|
4
|
+
// Helpers
|
|
6
5
|
function getAllUnitsFlat() {
|
|
7
6
|
const result = new Set();
|
|
8
7
|
|
|
@@ -19,7 +18,6 @@ export function createUnitsStore(initial = {}) {
|
|
|
19
18
|
|
|
20
19
|
// Avoid duplicate like "m" vs "meter"
|
|
21
20
|
if (unitLower !== keyLower) {
|
|
22
|
-
// Optional: only single-word units
|
|
23
21
|
if (unitLower.split(/\s+/).length === 1) {
|
|
24
22
|
result.add(unitLower);
|
|
25
23
|
}
|
|
@@ -41,6 +39,9 @@ export function createUnitsStore(initial = {}) {
|
|
|
41
39
|
return Array.from(result);
|
|
42
40
|
}
|
|
43
41
|
|
|
42
|
+
/**
|
|
43
|
+
* @param {string} input
|
|
44
|
+
*/
|
|
44
45
|
function findUnit(input) {
|
|
45
46
|
input = input.toLowerCase();
|
|
46
47
|
|
|
@@ -53,7 +54,7 @@ export function createUnitsStore(initial = {}) {
|
|
|
53
54
|
u.unit?.toLowerCase() === input ||
|
|
54
55
|
u.symbol?.toLowerCase() === input
|
|
55
56
|
) {
|
|
56
|
-
return { type, key
|
|
57
|
+
return { type, key, data: u };
|
|
57
58
|
}
|
|
58
59
|
}
|
|
59
60
|
}
|
|
@@ -61,68 +62,89 @@ export function createUnitsStore(initial = {}) {
|
|
|
61
62
|
return null;
|
|
62
63
|
}
|
|
63
64
|
|
|
64
|
-
|
|
65
|
-
|
|
65
|
+
/**
|
|
66
|
+
* @param {number} value
|
|
67
|
+
* @param {any} fromUnit
|
|
68
|
+
* @param {any} toUnit
|
|
69
|
+
*/
|
|
66
70
|
function convert(value, fromUnit, toUnit) {
|
|
67
|
-
|
|
68
|
-
|
|
71
|
+
const from = findUnit(fromUnit);
|
|
72
|
+
const to = findUnit(toUnit);
|
|
69
73
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
const result = value * (from.data.value / to.data.value);
|
|
74
|
+
if (!from) {
|
|
75
|
+
throw new Error(`Unknown unit: ${fromUnit}`);
|
|
76
|
+
}
|
|
77
|
+
if (!to) {
|
|
78
|
+
throw new Error(`Unknown unit: ${toUnit}`);
|
|
79
|
+
}
|
|
78
80
|
|
|
79
|
-
|
|
81
|
+
if (from.type !== to.type) {
|
|
82
|
+
throw new Error(
|
|
83
|
+
`Cannot convert ${fromUnit} to ${toUnit} (${to.data.unit || to.key}). ${from.data.unit || from.key} conversion units like ${Object.keys(units[from.type]).join(', ')}`
|
|
84
|
+
);
|
|
80
85
|
}
|
|
81
86
|
|
|
82
|
-
|
|
87
|
+
const result = value * (from.data.value / to.data.value);
|
|
83
88
|
|
|
89
|
+
return { value: result, unit: to.key };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Public API
|
|
84
93
|
return {
|
|
85
94
|
// Get all units
|
|
86
95
|
getUnits: () => units,
|
|
87
96
|
|
|
88
|
-
|
|
89
|
-
setUnits: (newUnits) => {
|
|
97
|
+
setUnits: (/** @type {{}} */ newUnits) => {
|
|
90
98
|
units = { ...newUnits };
|
|
91
99
|
},
|
|
92
100
|
|
|
93
|
-
|
|
94
|
-
updateType: (type, data) => {
|
|
101
|
+
updateType: (/** @type {string | number} */ type, /** @type {any} */ data) => {
|
|
95
102
|
units[type] = { ...units[type], ...data };
|
|
96
103
|
},
|
|
97
104
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
105
|
+
addUnit: (
|
|
106
|
+
/** @type {string | number} */ type,
|
|
107
|
+
/** @type {string | number} */ key,
|
|
108
|
+
/** @type {any} */ unitObj
|
|
109
|
+
) => {
|
|
110
|
+
if (!units[type]) {
|
|
111
|
+
units[type] = {};
|
|
112
|
+
}
|
|
101
113
|
units[type][key] = unitObj;
|
|
102
114
|
},
|
|
115
|
+
// Unit-aware arithmetic: unify operands to same unit type, then apply operator
|
|
116
|
+
/**
|
|
117
|
+
* @param {string} op
|
|
118
|
+
* @param {{ unit: any; value: any; }} left
|
|
119
|
+
* @param {{ unit: any; value: number; }} right
|
|
120
|
+
*/
|
|
103
121
|
compute(op, left, right) {
|
|
122
|
+
const isUnit = (/** @type {any} */ v) =>
|
|
123
|
+
v && typeof v === 'object' && 'value' in v && 'unit' in v;
|
|
104
124
|
|
|
105
|
-
const
|
|
106
|
-
v && typeof v === "object" && "value" in v && "unit" in v;
|
|
107
|
-
|
|
108
|
-
const apply = (a, b) => {
|
|
125
|
+
const apply = (/** @type {any} */ a, /** @type {any} */ b) => {
|
|
109
126
|
switch (op) {
|
|
110
|
-
case
|
|
111
|
-
|
|
112
|
-
case
|
|
113
|
-
|
|
114
|
-
case
|
|
115
|
-
|
|
127
|
+
case '+':
|
|
128
|
+
return a + b;
|
|
129
|
+
case '-':
|
|
130
|
+
return a - b;
|
|
131
|
+
case '*':
|
|
132
|
+
return a * b;
|
|
133
|
+
case '/':
|
|
134
|
+
return a / b;
|
|
135
|
+
case '%':
|
|
136
|
+
return a % b;
|
|
137
|
+
case '^':
|
|
138
|
+
return Math.pow(a, b);
|
|
116
139
|
}
|
|
117
140
|
};
|
|
118
141
|
|
|
119
142
|
// BOTH UNIT
|
|
120
143
|
if (isUnit(left) && isUnit(right)) {
|
|
121
|
-
|
|
122
144
|
const from = this.findUnit(right.unit);
|
|
123
145
|
const to = this.findUnit(left.unit);
|
|
124
146
|
|
|
125
|
-
if (from.type !== to.type) {
|
|
147
|
+
if (!from || !to || from.type !== to.type) {
|
|
126
148
|
throw new Error(`Cannot operate on different unit types`);
|
|
127
149
|
}
|
|
128
150
|
|
|
@@ -132,47 +154,47 @@ export function createUnitsStore(initial = {}) {
|
|
|
132
154
|
const result = apply(left.value, r);
|
|
133
155
|
|
|
134
156
|
// multiplication/division produce compound units
|
|
135
|
-
if (op ===
|
|
157
|
+
if (op === '*') {
|
|
136
158
|
return { value: result, unit: left.unit };
|
|
137
159
|
}
|
|
138
160
|
|
|
139
|
-
if (op ===
|
|
161
|
+
if (op === '/') {
|
|
140
162
|
return { value: result, unit: left.unit };
|
|
141
163
|
}
|
|
142
164
|
|
|
143
|
-
if (op ===
|
|
165
|
+
if (op === '^') {
|
|
144
166
|
return { value: result, unit: left.unit };
|
|
145
167
|
}
|
|
146
168
|
|
|
147
169
|
return { value: result, unit: left.unit };
|
|
148
170
|
}
|
|
149
171
|
|
|
150
|
-
//
|
|
172
|
+
// LEFT UNIT
|
|
151
173
|
if (isUnit(left) && !isUnit(right)) {
|
|
152
174
|
const result = apply(left.value, right);
|
|
153
175
|
|
|
154
176
|
return { value: result, unit: left.unit };
|
|
155
177
|
}
|
|
156
178
|
|
|
157
|
-
//
|
|
179
|
+
// RIGHT UNIT
|
|
158
180
|
if (!isUnit(left) && isUnit(right)) {
|
|
159
181
|
const result = apply(left, right.value);
|
|
160
182
|
|
|
161
|
-
if (op ===
|
|
183
|
+
if (op === '/') {
|
|
162
184
|
return { value: result, unit: right.unit };
|
|
163
185
|
}
|
|
164
186
|
|
|
165
187
|
return { value: result, unit: right.unit };
|
|
166
188
|
}
|
|
167
189
|
|
|
168
|
-
//
|
|
190
|
+
// NORMAL
|
|
169
191
|
return apply(left, right);
|
|
170
192
|
},
|
|
171
|
-
|
|
193
|
+
|
|
172
194
|
convert,
|
|
173
195
|
|
|
174
196
|
// Search helpers
|
|
175
197
|
getAllUnitsFlat,
|
|
176
|
-
findUnit
|
|
198
|
+
findUnit,
|
|
177
199
|
};
|
|
178
200
|
}
|
package/src/variables/store.js
CHANGED
|
@@ -2,18 +2,19 @@ const validVarName = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
|
|
|
2
2
|
|
|
3
3
|
export function createVarStore(initial = {}) {
|
|
4
4
|
let store = Object.create(null);
|
|
5
|
-
|
|
6
5
|
|
|
7
6
|
for (const key in initial) {
|
|
8
7
|
store[key] = initial[key];
|
|
9
8
|
}
|
|
10
9
|
|
|
11
10
|
return {
|
|
11
|
+
/**
|
|
12
|
+
* @param {string} name
|
|
13
|
+
* @param {number | undefined} value
|
|
14
|
+
*/
|
|
12
15
|
set(name, value, { override = true } = {}) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
if (typeof name !== "string" || !name) {
|
|
16
|
-
throw new Error("Variable name must be a non-empty string");
|
|
16
|
+
if (typeof name !== 'string' || !name) {
|
|
17
|
+
throw new Error('Variable name must be a non-empty string');
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
if (!validVarName.test(name)) {
|
|
@@ -26,50 +27,52 @@ export function createVarStore(initial = {}) {
|
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
// Prevent overwrite (optional)
|
|
29
|
-
if (!override && name in
|
|
30
|
+
if (!override && name in store) {
|
|
30
31
|
throw new Error(`Variable '${name}' already exists`);
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
store[name] = value;
|
|
34
35
|
},
|
|
35
36
|
|
|
36
|
-
|
|
37
|
+
/**
|
|
38
|
+
* @param {string | number} name
|
|
39
|
+
*/
|
|
37
40
|
get(name) {
|
|
38
41
|
return store[name];
|
|
39
42
|
},
|
|
40
43
|
|
|
41
|
-
|
|
44
|
+
/**
|
|
45
|
+
* @param {any} name
|
|
46
|
+
*/
|
|
42
47
|
has(name) {
|
|
43
48
|
return Object.prototype.hasOwnProperty.call(store, name);
|
|
44
49
|
},
|
|
45
50
|
|
|
46
|
-
|
|
51
|
+
/**
|
|
52
|
+
* @param {string | number} name
|
|
53
|
+
*/
|
|
47
54
|
remove(name) {
|
|
48
55
|
delete store[name];
|
|
49
56
|
},
|
|
50
57
|
|
|
51
|
-
// get all variables (snapshot)
|
|
52
58
|
all() {
|
|
53
59
|
return { ...store };
|
|
54
60
|
},
|
|
55
61
|
|
|
56
|
-
// clear all
|
|
57
62
|
clear() {
|
|
58
63
|
store = Object.create(null);
|
|
59
64
|
},
|
|
60
65
|
|
|
61
|
-
// merge multiple variables
|
|
62
66
|
merge(obj = {}) {
|
|
63
67
|
for (const key in obj) {
|
|
64
68
|
store[key] = obj[key];
|
|
65
69
|
}
|
|
66
70
|
},
|
|
67
71
|
|
|
68
|
-
// clone store (for scoped instances)
|
|
69
72
|
clone() {
|
|
70
73
|
return createVarStore(store);
|
|
71
|
-
}
|
|
74
|
+
},
|
|
72
75
|
};
|
|
73
76
|
}
|
|
74
77
|
|
|
75
|
-
export default { createVarStore };
|
|
78
|
+
export default { createVarStore };
|