@the-trybe/formula-engine 1.0.0

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.
Files changed (43) hide show
  1. package/.claude/settings.local.json +6 -0
  2. package/PRD_FORMULA_ENGINE.md +1863 -0
  3. package/README.md +382 -0
  4. package/dist/decimal-utils.d.ts +180 -0
  5. package/dist/decimal-utils.js +355 -0
  6. package/dist/dependency-extractor.d.ts +20 -0
  7. package/dist/dependency-extractor.js +103 -0
  8. package/dist/dependency-graph.d.ts +60 -0
  9. package/dist/dependency-graph.js +252 -0
  10. package/dist/errors.d.ts +161 -0
  11. package/dist/errors.js +260 -0
  12. package/dist/evaluator.d.ts +51 -0
  13. package/dist/evaluator.js +494 -0
  14. package/dist/formula-engine.d.ts +79 -0
  15. package/dist/formula-engine.js +355 -0
  16. package/dist/functions.d.ts +3 -0
  17. package/dist/functions.js +720 -0
  18. package/dist/index.d.ts +10 -0
  19. package/dist/index.js +61 -0
  20. package/dist/lexer.d.ts +25 -0
  21. package/dist/lexer.js +357 -0
  22. package/dist/parser.d.ts +32 -0
  23. package/dist/parser.js +372 -0
  24. package/dist/types.d.ts +228 -0
  25. package/dist/types.js +62 -0
  26. package/jest.config.js +23 -0
  27. package/package.json +35 -0
  28. package/src/decimal-utils.ts +408 -0
  29. package/src/dependency-extractor.ts +117 -0
  30. package/src/dependency-graph.test.ts +238 -0
  31. package/src/dependency-graph.ts +288 -0
  32. package/src/errors.ts +296 -0
  33. package/src/evaluator.ts +604 -0
  34. package/src/formula-engine.test.ts +660 -0
  35. package/src/formula-engine.ts +430 -0
  36. package/src/functions.ts +770 -0
  37. package/src/index.ts +103 -0
  38. package/src/lexer.test.ts +288 -0
  39. package/src/lexer.ts +394 -0
  40. package/src/parser.test.ts +349 -0
  41. package/src/parser.ts +449 -0
  42. package/src/types.ts +347 -0
  43. package/tsconfig.json +29 -0
@@ -0,0 +1,252 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DependencyGraphBuilder = exports.DependencyGraph = void 0;
4
+ const dependency_extractor_1 = require("./dependency-extractor");
5
+ const errors_1 = require("./errors");
6
+ class DependencyGraph {
7
+ constructor() {
8
+ this.nodes = new Set();
9
+ this.edges = new Map();
10
+ }
11
+ /**
12
+ * Add a node to the graph
13
+ */
14
+ addNode(id) {
15
+ this.nodes.add(id);
16
+ if (!this.edges.has(id)) {
17
+ this.edges.set(id, new Set());
18
+ }
19
+ }
20
+ /**
21
+ * Add an edge from source to target (source depends on target)
22
+ */
23
+ addEdge(source, target) {
24
+ this.addNode(source);
25
+ this.addNode(target);
26
+ this.edges.get(source).add(target);
27
+ }
28
+ /**
29
+ * Check if the graph has any cycles
30
+ */
31
+ hasCycles() {
32
+ try {
33
+ this.topologicalSort();
34
+ return false;
35
+ }
36
+ catch (error) {
37
+ return error instanceof errors_1.CircularDependencyError;
38
+ }
39
+ }
40
+ /**
41
+ * Get all root nodes (nodes with no dependencies)
42
+ */
43
+ getRoots() {
44
+ const roots = new Set();
45
+ for (const node of this.nodes) {
46
+ const deps = this.edges.get(node) || new Set();
47
+ if (deps.size === 0) {
48
+ roots.add(node);
49
+ }
50
+ }
51
+ return roots;
52
+ }
53
+ /**
54
+ * Get all nodes that depend on the given node
55
+ */
56
+ getDependents(nodeId) {
57
+ const dependents = new Set();
58
+ for (const [node, deps] of this.edges) {
59
+ if (deps.has(nodeId)) {
60
+ dependents.add(node);
61
+ }
62
+ }
63
+ return dependents;
64
+ }
65
+ /**
66
+ * Get direct dependencies of a node
67
+ */
68
+ getDependencies(nodeId) {
69
+ return this.edges.get(nodeId) || new Set();
70
+ }
71
+ /**
72
+ * Get all transitive dependencies of a node
73
+ */
74
+ getTransitiveDependencies(nodeId) {
75
+ const visited = new Set();
76
+ const result = new Set();
77
+ this.collectTransitiveDependencies(nodeId, visited, result);
78
+ result.delete(nodeId); // Don't include the node itself
79
+ return result;
80
+ }
81
+ collectTransitiveDependencies(nodeId, visited, result) {
82
+ if (visited.has(nodeId)) {
83
+ return;
84
+ }
85
+ visited.add(nodeId);
86
+ const deps = this.edges.get(nodeId);
87
+ if (deps) {
88
+ for (const dep of deps) {
89
+ result.add(dep);
90
+ this.collectTransitiveDependencies(dep, visited, result);
91
+ }
92
+ }
93
+ }
94
+ /**
95
+ * Perform topological sort using Kahn's algorithm
96
+ * Returns nodes in evaluation order (dependencies first)
97
+ * Throws CircularDependencyError if a cycle is detected
98
+ */
99
+ topologicalSort() {
100
+ // Calculate in-degree for each node
101
+ const inDegree = new Map();
102
+ for (const node of this.nodes) {
103
+ inDegree.set(node, 0);
104
+ }
105
+ // Count incoming edges for each node
106
+ for (const [, deps] of this.edges) {
107
+ for (const dep of deps) {
108
+ if (this.nodes.has(dep)) {
109
+ // We need to count how many nodes depend on this one
110
+ // This is actually reverse - we need dependents, not dependencies
111
+ }
112
+ }
113
+ }
114
+ // Actually, we need to build a reverse graph for proper topological sort
115
+ // edges: node -> dependencies means we need to evaluate dependencies first
116
+ // So the "in-degree" should count how many times a node is depended upon
117
+ const dependents = new Map();
118
+ for (const node of this.nodes) {
119
+ dependents.set(node, new Set());
120
+ }
121
+ for (const [node, deps] of this.edges) {
122
+ for (const dep of deps) {
123
+ if (dependents.has(dep)) {
124
+ dependents.get(dep).add(node);
125
+ }
126
+ }
127
+ }
128
+ // Calculate in-degree (number of dependencies)
129
+ for (const [node, deps] of this.edges) {
130
+ // Only count dependencies that are actual nodes in our graph
131
+ const validDeps = [...deps].filter(d => this.nodes.has(d));
132
+ inDegree.set(node, validDeps.length);
133
+ }
134
+ // Start with nodes that have no dependencies
135
+ const queue = [];
136
+ for (const [node, degree] of inDegree) {
137
+ if (degree === 0) {
138
+ queue.push(node);
139
+ }
140
+ }
141
+ const result = [];
142
+ const visited = new Set();
143
+ while (queue.length > 0) {
144
+ const node = queue.shift();
145
+ if (visited.has(node))
146
+ continue;
147
+ visited.add(node);
148
+ result.push(node);
149
+ // For each node that depends on this one, decrease its in-degree
150
+ const deps = dependents.get(node) || new Set();
151
+ for (const dependent of deps) {
152
+ const newDegree = (inDegree.get(dependent) || 0) - 1;
153
+ inDegree.set(dependent, newDegree);
154
+ if (newDegree === 0 && !visited.has(dependent)) {
155
+ queue.push(dependent);
156
+ }
157
+ }
158
+ }
159
+ // Check if all nodes were visited
160
+ if (result.length !== this.nodes.size) {
161
+ // There's a cycle - find it
162
+ const cycle = this.findCycle();
163
+ throw new errors_1.CircularDependencyError(cycle, [...this.nodes].filter(n => !visited.has(n)));
164
+ }
165
+ return result;
166
+ }
167
+ /**
168
+ * Find a cycle in the graph using DFS
169
+ */
170
+ findCycle() {
171
+ const visited = new Set();
172
+ const recursionStack = new Set();
173
+ const path = [];
174
+ const dfs = (node) => {
175
+ visited.add(node);
176
+ recursionStack.add(node);
177
+ path.push(node);
178
+ const deps = this.edges.get(node) || new Set();
179
+ for (const dep of deps) {
180
+ if (!this.nodes.has(dep))
181
+ continue;
182
+ if (!visited.has(dep)) {
183
+ const cycle = dfs(dep);
184
+ if (cycle)
185
+ return cycle;
186
+ }
187
+ else if (recursionStack.has(dep)) {
188
+ // Found a cycle - extract it from the path
189
+ const cycleStart = path.indexOf(dep);
190
+ const cycle = path.slice(cycleStart);
191
+ cycle.push(dep); // Close the cycle
192
+ return cycle;
193
+ }
194
+ }
195
+ path.pop();
196
+ recursionStack.delete(node);
197
+ return null;
198
+ };
199
+ for (const node of this.nodes) {
200
+ if (!visited.has(node)) {
201
+ const cycle = dfs(node);
202
+ if (cycle)
203
+ return cycle;
204
+ }
205
+ }
206
+ return [];
207
+ }
208
+ }
209
+ exports.DependencyGraph = DependencyGraph;
210
+ /**
211
+ * Build a dependency graph from formula definitions
212
+ */
213
+ class DependencyGraphBuilder {
214
+ constructor() {
215
+ this.extractor = new dependency_extractor_1.DependencyExtractor();
216
+ }
217
+ /**
218
+ * Build a dependency graph from formula definitions
219
+ */
220
+ build(formulas) {
221
+ const graph = new DependencyGraph();
222
+ // Create a map of formula IDs for quick lookup
223
+ const formulaIds = new Set(formulas.map(f => f.id));
224
+ // Add all formula IDs as nodes
225
+ for (const formula of formulas) {
226
+ graph.addNode(formula.id);
227
+ }
228
+ // Extract dependencies and add edges
229
+ for (const formula of formulas) {
230
+ const deps = formula.dependencies
231
+ ? new Set(formula.dependencies)
232
+ : this.extractor.extract(formula.expression);
233
+ for (const dep of deps) {
234
+ // Only add edges for dependencies that are other formulas
235
+ // (not external variables)
236
+ if (formulaIds.has(dep)) {
237
+ graph.addEdge(formula.id, dep);
238
+ }
239
+ }
240
+ }
241
+ return graph;
242
+ }
243
+ /**
244
+ * Get the evaluation order for a set of formulas
245
+ */
246
+ getEvaluationOrder(formulas) {
247
+ const graph = this.build(formulas);
248
+ return graph.topologicalSort();
249
+ }
250
+ }
251
+ exports.DependencyGraphBuilder = DependencyGraphBuilder;
252
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVwZW5kZW5jeS1ncmFwaC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9kZXBlbmRlbmN5LWdyYXBoLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUNBLGlFQUE2RDtBQUM3RCxxQ0FBbUQ7QUFFbkQsTUFBYSxlQUFlO0lBSTFCO1FBQ0UsSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLEdBQUcsRUFBRSxDQUFDO1FBQ3ZCLElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSxHQUFHLEVBQUUsQ0FBQztJQUN6QixDQUFDO0lBRUQ7O09BRUc7SUFDSCxPQUFPLENBQUMsRUFBVTtRQUNoQixJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUNuQixJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQztZQUN4QixJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsSUFBSSxHQUFHLEVBQUUsQ0FBQyxDQUFDO1FBQ2hDLENBQUM7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxPQUFPLENBQUMsTUFBYyxFQUFFLE1BQWM7UUFDcEMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUNyQixJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ3JCLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBRSxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUN0QyxDQUFDO0lBRUQ7O09BRUc7SUFDSCxTQUFTO1FBQ1AsSUFBSSxDQUFDO1lBQ0gsSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDO1lBQ3ZCLE9BQU8sS0FBSyxDQUFDO1FBQ2YsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixPQUFPLEtBQUssWUFBWSxnQ0FBdUIsQ0FBQztRQUNsRCxDQUFDO0lBQ0gsQ0FBQztJ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QyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztRQUVwRCwrQkFBK0I7UUFDL0IsS0FBSyxNQUFNLE9BQU8sSUFBSSxRQUFRLEVBQUUsQ0FBQztZQUMvQixLQUFLLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUM1QixDQUFDO1FBRUQscUNBQXFDO1FBQ3JDLEtBQUssTUFBTSxPQUFPLElBQUksUUFBUSxFQUFFLENBQUM7WUFDL0IsTUFBTSxJQUFJLEdBQUcsT0FBTyxDQUFDLFlBQVk7Z0JBQy9CLENBQUMsQ0FBQyxJQUFJLEdBQUcsQ0FBQyxPQUFPLENBQUMsWUFBWSxDQUFDO2dCQUMvQixDQUFDLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxDQUFDO1lBRS9DLEtBQUssTUFBTSxHQUFHLElBQUksSUFBSSxFQUFFLENBQUM7Z0JBQ3ZCLDBEQUEwRDtnQkFDMUQsMkJBQTJCO2dCQUMzQixJQUFJLFVBQVUsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztvQkFDeEIsS0FBSyxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsRUFBRSxFQUFFLEdBQUcsQ0FBQyxDQUFDO2dCQUNqQyxDQUFDO1lBQ0gsQ0FBQztRQUNILENBQUM7UUFFRCxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFFRDs7T0FFRztJQUNILGtCQUFrQixDQUFDLFFBQTZCO1FBQzlDLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDbkMsT0FBTyxLQUFLLENBQUMsZUFBZSxFQUFFLENBQUM7SUFDakMsQ0FBQztDQUNGO0FBOUNELHdEQThDQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IERlcGVuZGVuY3lHcmFwaCBhcyBJRGVwZW5kZW5jeUdyYXBoLCBGb3JtdWxhRGVmaW5pdGlvbiB9IGZyb20gJy4vdHlwZXMnO1xuaW1wb3J0IHsgRGVwZW5kZW5jeUV4dHJhY3RvciB9IGZyb20gJy4vZGVwZW5kZW5jeS1leHRyYWN0b3InO1xuaW1wb3J0IHsgQ2lyY3VsYXJEZXBlbmRlbmN5RXJyb3IgfSBmcm9tICcuL2Vycm9ycyc7XG5cbmV4cG9ydCBjbGFzcyBEZXBlbmRlbmN5R3JhcGggaW1wbGVtZW50cyBJRGVwZW5kZW5jeUdyYXBoIHtcbiAgbm9kZXM6IFNldDxzdHJpbmc+O1xuICBlZGdlczogTWFwPHN0cmluZywgU2V0PHN0cmluZz4+O1xuXG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIHRoaXMubm9kZXMgPSBuZXcgU2V0KCk7XG4gICAgdGhpcy5lZGdlcyA9IG5ldyBNYXAoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGQgYSBub2RlIHRvIHRoZSBncmFwaFxuICAgKi9cbiAgYWRkTm9kZShpZDogc3RyaW5nKTogdm9pZCB7XG4gICAgdGhpcy5ub2Rlcy5hZGQoaWQpO1xuICAgIGlmICghdGhpcy5lZGdlcy5oYXMoaWQpKSB7XG4gICAgICB0aGlzLmVkZ2VzLnNldChpZCwgbmV3IFNldCgpKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQWRkIGFuIGVkZ2UgZnJvbSBzb3VyY2UgdG8gdGFyZ2V0IChzb3VyY2UgZGVwZW5kcyBvbiB0YXJnZXQpXG4gICAqL1xuICBhZGRFZGdlKHNvdXJjZTogc3RyaW5nLCB0YXJnZXQ6IHN0cmluZyk6IHZvaWQge1xuICAgIHRoaXMuYWRkTm9kZShzb3VyY2UpO1xuICAgIHRoaXMuYWRkTm9kZSh0YXJnZXQpO1xuICAgIHRoaXMuZWRnZXMuZ2V0KHNvdXJjZSkhLmFkZCh0YXJnZXQpO1xuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrIGlmIHRoZSBncmFwaCBoYXMgYW55IGN5Y2xlc1xuICAgKi9cbiAgaGFzQ3ljbGVzKCk6IGJvb2xlYW4ge1xuICAgIHRyeSB7XG4gICAgICB0aGlzLnRvcG9sb2dpY2FsU29ydCgpO1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICByZXR1cm4gZXJyb3IgaW5zdGFuY2VvZiBDaXJjdWxhckRlcGVuZGVuY3lFcnJvcjtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogR2V0IGFsbCByb290IG5vZGVzIChub2RlcyB3aXRoIG5vIGRlcGVuZGVuY2llcylcbiAgICovXG4gIGdldFJvb3RzKCk6IFNldDxzdHJpbmc+IHtcbiAgICBjb25zdCByb290cyA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICAgIGZvciAoY29uc3Qgbm9kZSBvZiB0aGlzLm5vZGVzKSB7XG4gICAgICBjb25zdCBkZXBzID0gdGhpcy5lZGdlcy5nZXQobm9kZSkgfHwgbmV3IFNldCgpO1xuICAgICAgaWYgKGRlcHMuc2l6ZSA9PT0gMCkge1xuICAgICAgICByb290cy5hZGQobm9kZSk7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiByb290cztcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgYWxsIG5vZGVzIHRoYXQgZGVwZW5kIG9uIHRoZSBnaXZlbiBub2RlXG4gICAqL1xuICBnZXREZXBlbmRlbnRzKG5vZGVJZDogc3RyaW5nKTogU2V0PHN0cmluZz4ge1xuICAgIGNvbnN0IGRlcGVuZGVudHMgPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgICBmb3IgKGNvbnN0IFtub2RlLCBkZXBzXSBvZiB0aGlzLmVkZ2VzKSB7XG4gICAgICBpZiAoZGVwcy5oYXMobm9kZUlkKSkge1xuICAgICAgICBkZXBlbmRlbnRzLmFkZChub2RlKTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGRlcGVuZGVudHM7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGRpcmVjdCBkZXBlbmRlbmNpZXMgb2YgYSBub2RlXG4gICAqL1xuICBnZXREZXBlbmRlbmNpZXMobm9kZUlkOiBzdHJpbmcpOiBTZXQ8c3RyaW5nPiB7XG4gICAgcmV0dXJuIHRoaXMuZWRnZXMuZ2V0KG5vZGVJZCkgfHwgbmV3IFNldCgpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBhbGwgdHJhbnNpdGl2ZSBkZXBlbmRlbmNpZXMgb2YgYSBub2RlXG4gICAqL1xuICBnZXRUcmFuc2l0aXZlRGVwZW5kZW5jaWVzKG5vZGVJZDogc3RyaW5nKTogU2V0PHN0cmluZz4ge1xuICAgIGNvbnN0IHZpc2l0ZWQgPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgICBjb25zdCByZXN1bHQgPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgICB0aGlzLmNvbGxlY3RUcmFuc2l0aXZlRGVwZW5kZW5jaWVzKG5vZGVJZCwgdmlzaXRlZCwgcmVzdWx0KTtcbiAgICByZXN1bHQuZGVsZXRlKG5vZGVJZCk7IC8vIERvbid0IGluY2x1ZGUgdGhlIG5vZGUgaXRzZWxmXG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIHByaXZhdGUgY29sbGVjdFRyYW5zaXRpdmVEZXBlbmRlbmNpZXMoXG4gICAgbm9kZUlkOiBzdHJpbmcsXG4gICAgdmlzaXRlZDogU2V0PHN0cmluZz4sXG4gICAgcmVzdWx0OiBTZXQ8c3RyaW5nPlxuICApOiB2b2lkIHtcbiAgICBpZiAodmlzaXRlZC5oYXMobm9kZUlkKSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB2aXNpdGVkLmFkZChub2RlSWQpO1xuXG4gICAgY29uc3QgZGVwcyA9IHRoaXMuZWRnZXMuZ2V0KG5vZGVJZCk7XG4gICAgaWYgKGRlcHMpIHtcbiAgICAgIGZvciAoY29uc3QgZGVwIG9mIGRlcHMpIHtcbiAgICAgICAgcmVzdWx0LmFkZChkZXApO1xuICAgICAgICB0aGlzLmNvbGxlY3RUcmFuc2l0aXZlRGVwZW5kZW5jaWVzKGRlcCwgdmlzaXRlZCwgcmVzdWx0KTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUGVyZm9ybSB0b3BvbG9naWNhbCBzb3J0IHVzaW5nIEthaG4ncyBhbGdvcml0aG1cbiAgICogUmV0dXJucyBub2RlcyBpbiBldmFsdWF0aW9uIG9yZGVyIChkZXBlbmRlbmNpZXMgZmlyc3QpXG4gICAqIFRocm93cyBDaXJjdWxhckRlcGVuZGVuY3lFcnJvciBpZiBhIGN5Y2xlIGlzIGRldGVjdGVkXG4gICAqL1xuICB0b3BvbG9naWNhbFNvcnQoKTogc3RyaW5nW10ge1xuICAgIC8vIENhbGN1bGF0ZSBpbi1kZWdyZWUgZm9yIGVhY2ggbm9kZVxuICAgIGNvbnN0IGluRGVncmVlID0gbmV3IE1hcDxzdHJpbmcsIG51bWJlcj4oKTtcbiAgICBmb3IgKGNvbnN0IG5vZGUgb2YgdGhpcy5ub2Rlcykge1xuICAgICAgaW5EZWdyZWUuc2V0KG5vZGUsIDApO1xuICAgIH1cblxuICAgIC8vIENvdW50IGluY29taW5nIGVkZ2VzIGZvciBlYWNoIG5vZGVcbiAgICBmb3IgKGNvbnN0IFssIGRlcHNdIG9mIHRoaXMuZWRnZXMpIHtcbiAgICAgIGZvciAoY29uc3QgZGVwIG9mIGRlcHMpIHtcbiAgICAgICAgaWYgKHRoaXMubm9kZXMuaGFzKGRlcCkpIHtcbiAgICAgICAgICAvLyBXZSBuZWVkIHRvIGNvdW50IGhvdyBtYW55IG5vZGVzIGRlcGVuZCBvbiB0aGlzIG9uZVxuICAgICAgICAgIC8vIFRoaXMgaXMgYWN0dWFsbHkgcmV2ZXJzZSAtIHdlIG5lZWQgZGVwZW5kZW50cywgbm90IGRlcGVuZGVuY2llc1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gQWN0dWFsbHksIHdlIG5lZWQgdG8gYnVpbGQgYSByZXZlcnNlIGdyYXBoIGZvciBwcm9wZXIgdG9wb2xvZ2ljYWwgc29ydFxuICAgIC8vIGVkZ2VzOiBub2RlIC0+IGRlcGVuZGVuY2llcyBtZWFucyB3ZSBuZWVkIHRvIGV2YWx1YXRlIGRlcGVuZGVuY2llcyBmaXJzdFxuICAgIC8vIFNvIHRoZSBcImluLWRlZ3JlZVwiIHNob3VsZCBjb3VudCBob3cgbWFueSB0aW1lcyBhIG5vZGUgaXMgZGVwZW5kZWQgdXBvblxuXG4gICAgY29uc3QgZGVwZW5kZW50cyA9IG5ldyBNYXA8c3RyaW5nLCBTZXQ8c3RyaW5nPj4oKTtcbiAgICBmb3IgKGNvbnN0IG5vZGUgb2YgdGhpcy5ub2Rlcykge1xuICAgICAgZGVwZW5kZW50cy5zZXQobm9kZSwgbmV3IFNldCgpKTtcbiAgICB9XG5cbiAgICBmb3IgKGNvbnN0IFtub2RlLCBkZXBzXSBvZiB0aGlzLmVkZ2VzKSB7XG4gICAgICBmb3IgKGNvbnN0IGRlcCBvZiBkZXBzKSB7XG4gICAgICAgIGlmIChkZXBlbmRlbnRzLmhhcyhkZXApKSB7XG4gICAgICAgICAgZGVwZW5kZW50cy5nZXQoZGVwKSEuYWRkKG5vZGUpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gQ2FsY3VsYXRlIGluLWRlZ3JlZSAobnVtYmVyIG9mIGRlcGVuZGVuY2llcylcbiAgICBmb3IgKGNvbnN0IFtub2RlLCBkZXBzXSBvZiB0aGlzLmVkZ2VzKSB7XG4gICAgICAvLyBPbmx5IGNvdW50IGRlcGVuZGVuY2llcyB0aGF0IGFyZSBhY3R1YWwgbm9kZXMgaW4gb3VyIGdyYXBoXG4gICAgICBjb25zdCB2YWxpZERlcHMgPSBbLi4uZGVwc10uZmlsdGVyKGQgPT4gdGhpcy5ub2Rlcy5oYXMoZCkpO1xuICAgICAgaW5EZWdyZWUuc2V0KG5vZGUsIHZhbGlkRGVwcy5sZW5ndGgpO1xuICAgIH1cblxuICAgIC8vIFN0YXJ0IHdpdGggbm9kZXMgdGhhdCBoYXZlIG5vIGRlcGVuZGVuY2llc1xuICAgIGNvbnN0IHF1ZXVlOiBzdHJpbmdbXSA9IFtdO1xuICAgIGZvciAoY29uc3QgW25vZGUsIGRlZ3JlZV0gb2YgaW5EZWdyZWUpIHtcbiAgICAgIGlmIChkZWdyZWUgPT09IDApIHtcbiAgICAgICAgcXVldWUucHVzaChub2RlKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBjb25zdCByZXN1bHQ6IHN0cmluZ1tdID0gW107XG4gICAgY29uc3QgdmlzaXRlZCA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuXG4gICAgd2hpbGUgKHF1ZXVlLmxlbmd0aCA+IDApIHtcbiAgICAgIGNvbnN0IG5vZGUgPSBxdWV1ZS5zaGlmdCgpITtcbiAgICAgIGlmICh2aXNpdGVkLmhhcyhub2RlKSkgY29udGludWU7XG5cbiAgICAgIHZpc2l0ZWQuYWRkKG5vZGUpO1xuICAgICAgcmVzdWx0LnB1c2gobm9kZSk7XG5cbiAgICAgIC8vIEZvciBlYWNoIG5vZGUgdGhhdCBkZXBlbmRzIG9uIHRoaXMgb25lLCBkZWNyZWFzZSBpdHMgaW4tZGVncmVlXG4gICAgICBjb25zdCBkZXBzID0gZGVwZW5kZW50cy5nZXQobm9kZSkgfHwgbmV3IFNldCgpO1xuICAgICAgZm9yIChjb25zdCBkZXBlbmRlbnQgb2YgZGVwcykge1xuICAgICAgICBjb25zdCBuZXdEZWdyZWUgPSAoaW5EZWdyZWUuZ2V0KGRlcGVuZGVudCkgfHwgMCkgLSAxO1xuICAgICAgICBpbkRlZ3JlZS5zZXQoZGVwZW5kZW50LCBuZXdEZWdyZWUpO1xuICAgICAgICBpZiAobmV3RGVncmVlID09PSAwICYmICF2aXNpdGVkLmhhcyhkZXBlbmRlbnQpKSB7XG4gICAgICAgICAgcXVldWUucHVzaChkZXBlbmRlbnQpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gQ2hlY2sgaWYgYWxsIG5vZGVzIHdlcmUgdmlzaXRlZFxuICAgIGlmIChyZXN1bHQubGVuZ3RoICE9PSB0aGlzLm5vZGVzLnNpemUpIHtcbiAgICAgIC8vIFRoZXJlJ3MgYSBjeWNsZSAtIGZpbmQgaXRcbiAgICAgIGNvbnN0IGN5Y2xlID0gdGhpcy5maW5kQ3ljbGUoKTtcbiAgICAgIHRocm93IG5ldyBDaXJjdWxhckRlcGVuZGVuY3lFcnJvcihjeWNsZSwgWy4uLnRoaXMubm9kZXNdLmZpbHRlcihuID0+ICF2aXNpdGVkLmhhcyhuKSkpO1xuICAgIH1cblxuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cblxuICAvKipcbiAgICogRmluZCBhIGN5Y2xlIGluIHRoZSBncmFwaCB1c2luZyBERlNcbiAgICovXG4gIHByaXZhdGUgZmluZEN5Y2xlKCk6IHN0cmluZ1tdIHtcbiAgICBjb25zdCB2aXNpdGVkID0gbmV3IFNldDxzdHJpbmc+KCk7XG4gICAgY29uc3QgcmVjdXJzaW9uU3RhY2sgPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgICBjb25zdCBwYXRoOiBzdHJpbmdbXSA9IFtdO1xuXG4gICAgY29uc3QgZGZzID0gKG5vZGU6IHN0cmluZyk6IHN0cmluZ1tdIHwgbnVsbCA9PiB7XG4gICAgICB2aXNpdGVkLmFkZChub2RlKTtcbiAgICAgIHJlY3Vyc2lvblN0YWNrLmFkZChub2RlKTtcbiAgICAgIHBhdGgucHVzaChub2RlKTtcblxuICAgICAgY29uc3QgZGVwcyA9IHRoaXMuZWRnZXMuZ2V0KG5vZGUpIHx8IG5ldyBTZXQoKTtcbiAgICAgIGZvciAoY29uc3QgZGVwIG9mIGRlcHMpIHtcbiAgICAgICAgaWYgKCF0aGlzLm5vZGVzLmhhcyhkZXApKSBjb250aW51ZTtcblxuICAgICAgICBpZiAoIXZpc2l0ZWQuaGFzKGRlcCkpIHtcbiAgICAgICAgICBjb25zdCBjeWNsZSA9IGRmcyhkZXApO1xuICAgICAgICAgIGlmIChjeWNsZSkgcmV0dXJuIGN5Y2xlO1xuICAgICAgICB9IGVsc2UgaWYgKHJlY3Vyc2lvblN0YWNrLmhhcyhkZXApKSB7XG4gICAgICAgICAgLy8gRm91bmQgYSBjeWNsZSAtIGV4dHJhY3QgaXQgZnJvbSB0aGUgcGF0aFxuICAgICAgICAgIGNvbnN0IGN5Y2xlU3RhcnQgPSBwYXRoLmluZGV4T2YoZGVwKTtcbiAgICAgICAgICBjb25zdCBjeWNsZSA9IHBhdGguc2xpY2UoY3ljbGVTdGFydCk7XG4gICAgICAgICAgY3ljbGUucHVzaChkZXApOyAvLyBDbG9zZSB0aGUgY3ljbGVcbiAgICAgICAgICByZXR1cm4gY3ljbGU7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcGF0aC5wb3AoKTtcbiAgICAgIHJlY3Vyc2lvblN0YWNrLmRlbGV0ZShub2RlKTtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH07XG5cbiAgICBmb3IgKGNvbnN0IG5vZGUgb2YgdGhpcy5ub2Rlcykge1xuICAgICAgaWYgKCF2aXNpdGVkLmhhcyhub2RlKSkge1xuICAgICAgICBjb25zdCBjeWNsZSA9IGRmcyhub2RlKTtcbiAgICAgICAgaWYgKGN5Y2xlKSByZXR1cm4gY3ljbGU7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIFtdO1xuICB9XG59XG5cbi8qKlxuICogQnVpbGQgYSBkZXBlbmRlbmN5IGdyYXBoIGZyb20gZm9ybXVsYSBkZWZpbml0aW9uc1xuICovXG5leHBvcnQgY2xhc3MgRGVwZW5kZW5jeUdyYXBoQnVpbGRlciB7XG4gIHByaXZhdGUgZXh0cmFjdG9yOiBEZXBlbmRlbmN5RXh0cmFjdG9yO1xuXG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIHRoaXMuZXh0cmFjdG9yID0gbmV3IERlcGVuZGVuY3lFeHRyYWN0b3IoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBCdWlsZCBhIGRlcGVuZGVuY3kgZ3JhcGggZnJvbSBmb3JtdWxhIGRlZmluaXRpb25zXG4gICAqL1xuICBidWlsZChmb3JtdWxhczogRm9ybXVsYURlZmluaXRpb25bXSk6IERlcGVuZGVuY3lHcmFwaCB7XG4gICAgY29uc3QgZ3JhcGggPSBuZXcgRGVwZW5kZW5jeUdyYXBoKCk7XG5cbiAgICAvLyBDcmVhdGUgYSBtYXAgb2YgZm9ybXVsYSBJRHMgZm9yIHF1aWNrIGxvb2t1cFxuICAgIGNvbnN0IGZvcm11bGFJZHMgPSBuZXcgU2V0KGZvcm11bGFzLm1hcChmID0+IGYuaWQpKTtcblxuICAgIC8vIEFkZCBhbGwgZm9ybXVsYSBJRHMgYXMgbm9kZXNcbiAgICBmb3IgKGNvbnN0IGZvcm11bGEgb2YgZm9ybXVsYXMpIHtcbiAgICAgIGdyYXBoLmFkZE5vZGUoZm9ybXVsYS5pZCk7XG4gICAgfVxuXG4gICAgLy8gRXh0cmFjdCBkZXBlbmRlbmNpZXMgYW5kIGFkZCBlZGdlc1xuICAgIGZvciAoY29uc3QgZm9ybXVsYSBvZiBmb3JtdWxhcykge1xuICAgICAgY29uc3QgZGVwcyA9IGZvcm11bGEuZGVwZW5kZW5jaWVzXG4gICAgICAgID8gbmV3IFNldChmb3JtdWxhLmRlcGVuZGVuY2llcylcbiAgICAgICAgOiB0aGlzLmV4dHJhY3Rvci5leHRyYWN0KGZvcm11bGEuZXhwcmVzc2lvbik7XG5cbiAgICAgIGZvciAoY29uc3QgZGVwIG9mIGRlcHMpIHtcbiAgICAgICAgLy8gT25seSBhZGQgZWRnZXMgZm9yIGRlcGVuZGVuY2llcyB0aGF0IGFyZSBvdGhlciBmb3JtdWxhc1xuICAgICAgICAvLyAobm90IGV4dGVybmFsIHZhcmlhYmxlcylcbiAgICAgICAgaWYgKGZvcm11bGFJZHMuaGFzKGRlcCkpIHtcbiAgICAgICAgICBncmFwaC5hZGRFZGdlKGZvcm11bGEuaWQsIGRlcCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gZ3JhcGg7XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRoZSBldmFsdWF0aW9uIG9yZGVyIGZvciBhIHNldCBvZiBmb3JtdWxhc1xuICAgKi9cbiAgZ2V0RXZhbHVhdGlvbk9yZGVyKGZvcm11bGFzOiBGb3JtdWxhRGVmaW5pdGlvbltdKTogc3RyaW5nW10ge1xuICAgIGNvbnN0IGdyYXBoID0gdGhpcy5idWlsZChmb3JtdWxhcyk7XG4gICAgcmV0dXJuIGdyYXBoLnRvcG9sb2dpY2FsU29ydCgpO1xuICB9XG59XG4iXX0=
@@ -0,0 +1,161 @@
1
+ import { ValueType } from './types';
2
+ export type ErrorCategory = 'PARSE' | 'VALIDATION' | 'EVALUATION' | 'CONFIGURATION';
3
+ export declare abstract class FormulaEngineError extends Error {
4
+ abstract readonly code: string;
5
+ abstract readonly category: ErrorCategory;
6
+ constructor(message: string);
7
+ }
8
+ export declare class SyntaxError extends FormulaEngineError {
9
+ position: number;
10
+ line: number;
11
+ column: number;
12
+ expression: string;
13
+ readonly code = "PARSE_SYNTAX_ERROR";
14
+ readonly category: ErrorCategory;
15
+ constructor(message: string, position: number, line: number, column: number, expression: string);
16
+ }
17
+ export declare class UnexpectedTokenError extends FormulaEngineError {
18
+ token: string;
19
+ expected: string[];
20
+ position: number;
21
+ readonly code = "PARSE_UNEXPECTED_TOKEN";
22
+ readonly category: ErrorCategory;
23
+ constructor(token: string, expected: string[], position: number);
24
+ }
25
+ export declare class UnterminatedStringError extends FormulaEngineError {
26
+ readonly code = "PARSE_UNTERMINATED_STRING";
27
+ readonly category: ErrorCategory;
28
+ constructor(position: number);
29
+ }
30
+ export declare class InvalidNumberError extends FormulaEngineError {
31
+ readonly code = "PARSE_INVALID_NUMBER";
32
+ readonly category: ErrorCategory;
33
+ constructor(value: string, position: number);
34
+ }
35
+ export declare class CircularDependencyError extends FormulaEngineError {
36
+ cycle: string[];
37
+ involvedFormulas: string[];
38
+ readonly code = "VALIDATION_CIRCULAR_DEPENDENCY";
39
+ readonly category: ErrorCategory;
40
+ constructor(cycle: string[], involvedFormulas: string[]);
41
+ }
42
+ export declare class UndefinedVariableError extends FormulaEngineError {
43
+ variableName: string;
44
+ expression: string;
45
+ readonly code = "VALIDATION_UNDEFINED_VARIABLE";
46
+ readonly category: ErrorCategory;
47
+ constructor(variableName: string, expression: string);
48
+ }
49
+ export declare class UndefinedFunctionError extends FormulaEngineError {
50
+ functionName: string;
51
+ readonly code = "VALIDATION_UNDEFINED_FUNCTION";
52
+ readonly category: ErrorCategory;
53
+ constructor(functionName: string);
54
+ }
55
+ export declare class DuplicateFormulaError extends FormulaEngineError {
56
+ formulaId: string;
57
+ readonly code = "VALIDATION_DUPLICATE_FORMULA";
58
+ readonly category: ErrorCategory;
59
+ constructor(formulaId: string);
60
+ }
61
+ export declare class DivisionByZeroError extends FormulaEngineError {
62
+ readonly code = "EVAL_DIVISION_BY_ZERO";
63
+ readonly category: ErrorCategory;
64
+ constructor();
65
+ }
66
+ export declare class TypeMismatchError extends FormulaEngineError {
67
+ expected: ValueType | ValueType[] | string;
68
+ actual: ValueType | string;
69
+ context: string;
70
+ readonly code = "EVAL_TYPE_MISMATCH";
71
+ readonly category: ErrorCategory;
72
+ constructor(expected: ValueType | ValueType[] | string, actual: ValueType | string, context: string);
73
+ }
74
+ export declare class ArgumentCountError extends FormulaEngineError {
75
+ functionName: string;
76
+ expected: {
77
+ min: number;
78
+ max: number;
79
+ };
80
+ actual: number;
81
+ readonly code = "EVAL_ARGUMENT_COUNT";
82
+ readonly category: ErrorCategory;
83
+ constructor(functionName: string, expected: {
84
+ min: number;
85
+ max: number;
86
+ }, actual: number);
87
+ }
88
+ export declare class InvalidOperationError extends FormulaEngineError {
89
+ operator: string;
90
+ operandTypes: string[];
91
+ readonly code = "EVAL_INVALID_OPERATION";
92
+ readonly category: ErrorCategory;
93
+ constructor(operator: string, operandTypes: string[]);
94
+ }
95
+ export declare class PropertyAccessError extends FormulaEngineError {
96
+ property: string;
97
+ objectType: string;
98
+ readonly code = "EVAL_PROPERTY_ACCESS";
99
+ readonly category: ErrorCategory;
100
+ constructor(property: string, objectType: string);
101
+ }
102
+ export declare class IndexAccessError extends FormulaEngineError {
103
+ index: unknown;
104
+ objectType: string;
105
+ readonly code = "EVAL_INDEX_ACCESS";
106
+ readonly category: ErrorCategory;
107
+ constructor(index: unknown, objectType: string);
108
+ }
109
+ export declare class DecimalError extends FormulaEngineError {
110
+ readonly code: string;
111
+ readonly category: ErrorCategory;
112
+ constructor(message: string);
113
+ }
114
+ export declare class DecimalOverflowError extends DecimalError {
115
+ value: string;
116
+ maxExponent: number;
117
+ readonly code: string;
118
+ constructor(value: string, maxExponent: number);
119
+ }
120
+ export declare class DecimalUnderflowError extends DecimalError {
121
+ value: string;
122
+ minExponent: number;
123
+ readonly code: string;
124
+ constructor(value: string, minExponent: number);
125
+ }
126
+ export declare class DecimalDivisionByZeroError extends DecimalError {
127
+ readonly code: string;
128
+ constructor();
129
+ }
130
+ export declare class InvalidDecimalError extends DecimalError {
131
+ input: string;
132
+ readonly code: string;
133
+ constructor(input: string);
134
+ }
135
+ export declare class ConfigurationError extends FormulaEngineError {
136
+ readonly code = "CONFIGURATION_ERROR";
137
+ readonly category: ErrorCategory;
138
+ constructor(message: string);
139
+ }
140
+ export declare class SecurityError extends FormulaEngineError {
141
+ readonly code: string;
142
+ readonly category: ErrorCategory;
143
+ constructor(message: string);
144
+ }
145
+ export declare class MaxIterationsError extends SecurityError {
146
+ readonly code: string;
147
+ constructor(limit: number);
148
+ }
149
+ export declare class MaxRecursionError extends SecurityError {
150
+ readonly code: string;
151
+ constructor(limit: number);
152
+ }
153
+ export declare class MaxExpressionLengthError extends SecurityError {
154
+ readonly code: string;
155
+ constructor(length: number, limit: number);
156
+ }
157
+ export declare class GeneralFormulaError extends FormulaEngineError {
158
+ readonly code: string;
159
+ readonly category: ErrorCategory;
160
+ constructor(message: string);
161
+ }