exprify 1.0.2 → 1.0.3

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.
@@ -0,0 +1,178 @@
1
+ export function createUnitsStore(initial = {}) {
2
+ let units = { ...initial};
3
+
4
+ // ---------- Helpers ----------
5
+
6
+ function getAllUnitsFlat() {
7
+ const result = new Set();
8
+
9
+ for (const type in units) {
10
+ for (const key in units[type]) {
11
+ const u = units[type][key];
12
+
13
+ const keyLower = key.toLowerCase();
14
+ result.add(keyLower);
15
+
16
+ // Unit name
17
+ if (u.unit) {
18
+ const unitLower = u.unit.toLowerCase();
19
+
20
+ // Avoid duplicate like "m" vs "meter"
21
+ if (unitLower !== keyLower) {
22
+ // Optional: only single-word units
23
+ if (unitLower.split(/\s+/).length === 1) {
24
+ result.add(unitLower);
25
+ }
26
+ }
27
+ }
28
+
29
+ // Symbol
30
+ if (u.symbol) {
31
+ const symbolLower = u.symbol.toLowerCase();
32
+
33
+ // Avoid duplicate with unit name
34
+ if (!u.unit || symbolLower !== u.unit.toLowerCase()) {
35
+ result.add(symbolLower);
36
+ }
37
+ }
38
+ }
39
+ }
40
+
41
+ return Array.from(result);
42
+ }
43
+
44
+ function findUnit(input) {
45
+ input = input.toLowerCase();
46
+
47
+ for (const type in units) {
48
+ for (const key in units[type]) {
49
+ const u = units[type][key];
50
+
51
+ if (
52
+ key.toLowerCase() === input ||
53
+ u.unit?.toLowerCase() === input ||
54
+ u.symbol?.toLowerCase() === input
55
+ ) {
56
+ return { type, key , data: u};
57
+ }
58
+ }
59
+ }
60
+
61
+ return null;
62
+ }
63
+
64
+ // ---------- Core Convert ----------
65
+
66
+ function convert(value, fromUnit, toUnit) {
67
+ const from = findUnit(fromUnit);
68
+ const to = findUnit(toUnit);
69
+
70
+ if (!from) throw new Error(`Unknown unit: ${fromUnit}`);
71
+ if (!to) throw new Error(`Unknown unit: ${toUnit}`);
72
+
73
+ if (from.type !== to.type) {
74
+ throw new Error(`Cannot convert ${fromUnit} to ${toUnit} (${to.data.unit || to.key}). ${from.data.unit || from.key} conversion units like ${Object.keys(units[from.type]).join(", ")}`);
75
+ }
76
+
77
+ const result = value * (from.data.value / to.data.value);
78
+
79
+ return { value: result, unit: to.key };
80
+ }
81
+
82
+ // ---------- Public API ----------
83
+
84
+ return {
85
+ // Get all units
86
+ getUnits: () => units,
87
+
88
+ // Replace all units
89
+ setUnits: (newUnits) => {
90
+ units = { ...newUnits };
91
+ },
92
+
93
+ // Update single type
94
+ updateType: (type, data) => {
95
+ units[type] = { ...units[type], ...data };
96
+ },
97
+
98
+ // Add new unit
99
+ addUnit: (type, key, unitObj) => {
100
+ if (!units[type]) units[type] = {};
101
+ units[type][key] = unitObj;
102
+ },
103
+ compute(op, left, right) {
104
+
105
+ const isUnit = (v) =>
106
+ v && typeof v === "object" && "value" in v && "unit" in v;
107
+
108
+ const apply = (a, b) => {
109
+ switch (op) {
110
+ case "+": return a + b;
111
+ case "-": return a - b;
112
+ case "*": return a * b;
113
+ case "/": return a / b;
114
+ case "%": return a % b;
115
+ case "^": return Math.pow(a, b);
116
+ }
117
+ };
118
+
119
+ // BOTH UNIT
120
+ if (isUnit(left) && isUnit(right)) {
121
+
122
+ const from = this.findUnit(right.unit);
123
+ const to = this.findUnit(left.unit);
124
+
125
+ if (from.type !== to.type) {
126
+ throw new Error(`Cannot operate on different unit types`);
127
+ }
128
+
129
+ // convert right → left unit
130
+ const r = right.value * (from.data.value / to.data.value);
131
+
132
+ const result = apply(left.value, r);
133
+
134
+ // multiplication/division produce compound units
135
+ if (op === "*") {
136
+ return { value: result, unit: left.unit };
137
+ }
138
+
139
+ if (op === "/") {
140
+ return { value: result, unit: left.unit };
141
+ }
142
+
143
+ if (op === "^") {
144
+ return { value: result, unit: left.unit };
145
+ }
146
+
147
+ return { value: result, unit: left.unit };
148
+ }
149
+
150
+ // ================= LEFT UNIT =================
151
+ if (isUnit(left) && !isUnit(right)) {
152
+ const result = apply(left.value, right);
153
+
154
+ return { value: result, unit: left.unit };
155
+ }
156
+
157
+ // ================= RIGHT UNIT =================
158
+ if (!isUnit(left) && isUnit(right)) {
159
+ const result = apply(left, right.value);
160
+
161
+ if (op === "/") {
162
+ return { value: result, unit: right.unit };
163
+ }
164
+
165
+ return { value: result, unit: right.unit };
166
+ }
167
+
168
+ // ================= NORMAL =================
169
+ return apply(left, right);
170
+ },
171
+ // Convert
172
+ convert,
173
+
174
+ // Search helpers
175
+ getAllUnitsFlat,
176
+ findUnit
177
+ };
178
+ }
@@ -0,0 +1,75 @@
1
+ const validVarName = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
2
+
3
+ export function createVarStore(initial = {}) {
4
+ let store = Object.create(null);
5
+
6
+
7
+ for (const key in initial) {
8
+ store[key] = initial[key];
9
+ }
10
+
11
+ return {
12
+ set(name, value, { override = true } = {}) {
13
+
14
+ // Name validation
15
+ if (typeof name !== "string" || !name) {
16
+ throw new Error("Variable name must be a non-empty string");
17
+ }
18
+
19
+ if (!validVarName.test(name)) {
20
+ throw new Error(`Variable Name Error: '${name}' is not a valid variable name`);
21
+ }
22
+
23
+ // Value validation
24
+ if (value === undefined) {
25
+ throw new Error(`Variable Value Error: '${name}' cannot be undefined`);
26
+ }
27
+
28
+ // Prevent overwrite (optional)
29
+ if (!override && name in variablesDB) {
30
+ throw new Error(`Variable '${name}' already exists`);
31
+ }
32
+
33
+ store[name] = value;
34
+ },
35
+
36
+ //get variable
37
+ get(name) {
38
+ return store[name];
39
+ },
40
+
41
+ // check existence
42
+ has(name) {
43
+ return Object.prototype.hasOwnProperty.call(store, name);
44
+ },
45
+
46
+ // remove variable
47
+ remove(name) {
48
+ delete store[name];
49
+ },
50
+
51
+ // get all variables (snapshot)
52
+ all() {
53
+ return { ...store };
54
+ },
55
+
56
+ // clear all
57
+ clear() {
58
+ store = Object.create(null);
59
+ },
60
+
61
+ // merge multiple variables
62
+ merge(obj = {}) {
63
+ for (const key in obj) {
64
+ store[key] = obj[key];
65
+ }
66
+ },
67
+
68
+ // clone store (for scoped instances)
69
+ clone() {
70
+ return createVarStore(store);
71
+ }
72
+ };
73
+ }
74
+
75
+ export default { createVarStore };
package/docs/README.md DELETED
@@ -1,34 +0,0 @@
1
- ---
2
- layout: default
3
- title: Exprify Docs
4
- ---
5
-
6
- # Exprify Docs
7
-
8
- Exprify is a JavaScript expression parser and evaluator for math-heavy apps.
9
-
10
- ## Highlights
11
-
12
- - arithmetic, precedence, bigint, and booleans
13
- - variables, assignments, and inline functions
14
- - unit conversion
15
- - matrices and linear algebra helpers
16
- - complex numbers
17
- - symbolic helpers like `simplify`, `derivative`, and `rationalize`
18
-
19
- ## Quick Example
20
-
21
- ```js
22
- import Exprify from "exprify";
23
-
24
- const expr = new Exprify();
25
-
26
- expr.evaluate("hyp(a, b) = sqrt(a ^ 2 + b ^ 2)");
27
- console.log(expr.evaluate("hyp(3, 4)"));
28
- // 5
29
- ```
30
-
31
- ## References
32
-
33
- - [Project README](../README.md)
34
- - [Token Type Notes](./tokenType.txt)
@@ -1,4 +0,0 @@
1
- ---
2
- ---
3
-
4
- @import "jekyll-theme-primer";
@@ -1,21 +0,0 @@
1
- Token notes for Exprify
2
-
3
- - Number
4
- - BigInt
5
- - Boolean
6
- - String
7
- - Identifier
8
- - Function
9
- - Operator
10
- - UnaryOperator
11
- - Keyword
12
- - Unit
13
- - NumberWithUnit
14
- - ImaginaryLiteral
15
- - Parenthesis
16
- - ArrayStart / ArrayEnd
17
- - BlockStart / BlockEnd
18
- - Comma
19
- - Semicolon
20
- - Colon
21
- - Dot