@reekon-tools/boldr-utils 1.4.13 → 1.4.15

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.
@@ -41,13 +41,60 @@ export function evaluateFormula({ expression, mappings, valueMap, unit, formulas
41
41
  if (scope) {
42
42
  try {
43
43
  const normalizedUnit = normalizeUnitForMathJS(unit);
44
- const compiled = compile(expression);
45
- const result = compiled.evaluate(scope);
46
- const asUnit = mathUnit(result, normalizedUnit);
44
+ let compiled;
45
+ try {
46
+ compiled = compile(expression);
47
+ }
48
+ catch (compileErr) {
49
+ console.error(`Failed to compile formula expression`, compileErr);
50
+ return null;
51
+ }
52
+ let result;
53
+ try {
54
+ result = compiled.evaluate(scope);
55
+ }
56
+ catch (evalErr) {
57
+ // Handle divide by zero and other math errors
58
+ const errorMessage = evalErr instanceof Error ? evalErr.message : String(evalErr);
59
+ if (errorMessage.includes('divide') ||
60
+ errorMessage.includes('division') ||
61
+ errorMessage.includes('/') ||
62
+ errorMessage.includes('Division by zero') ||
63
+ errorMessage.includes('Cannot divide by zero')) {
64
+ console.error(`Division by zero in formula`, evalErr);
65
+ return null;
66
+ }
67
+ console.error(`Failed to evaluate formula`, evalErr);
68
+ return null;
69
+ }
70
+ // Check for invalid results (Infinity, NaN)
71
+ if (Number.isNaN(result)) {
72
+ console.error(`Formula result is NaN`);
73
+ return null;
74
+ }
75
+ if (!Number.isFinite(result)) {
76
+ console.error(`Formula result is Infinity`);
77
+ return null;
78
+ }
79
+ let asUnit;
80
+ try {
81
+ asUnit = mathUnit(result, normalizedUnit);
82
+ }
83
+ catch (unitErr) {
84
+ console.error(`Failed to convert result to unit`, unitErr);
85
+ return null;
86
+ }
47
87
  if (!asUnit.equalBase(mathUnit('1 um'))) {
48
- throw new Error(`Incompatible unit: ${asUnit.formatUnits()} is not compatible with ${normalizedUnit}`);
88
+ console.error(`Incompatible unit: ${asUnit.formatUnits()} is not compatible with ${normalizedUnit}`);
89
+ return null;
49
90
  }
50
- return Math.round(asUnit.toNumber('um'));
91
+ const finalResult = Math.round(asUnit.toNumber('um'));
92
+ // Check if final result is valid
93
+ if (!Number.isFinite(finalResult)) {
94
+ console.error(`Formula result is not a finite number`);
95
+ return null;
96
+ }
97
+ return finalResult;
51
98
  }
52
99
  catch (err) {
53
100
  console.error(`Failed to evaluate formula`, err);
@@ -95,23 +142,72 @@ export function evaluateFormula({ expression, mappings, valueMap, unit, formulas
95
142
  }
96
143
  // Recursively evaluate the referenced formula
97
144
  const nestedResult = evaluateNestedFormula(referencedFormula.id, referencedFormula.expression, referencedFormula.variableToColumnMap);
98
- // Convert result to current unit
99
- const resultInUnit = mathUnit(nestedResult, 'um').toNumber(normalizedUnit);
145
+ // Convert result to current unit with error handling
146
+ let resultInUnit;
147
+ try {
148
+ resultInUnit = mathUnit(nestedResult, 'um').toNumber(normalizedUnit);
149
+ }
150
+ catch (unitErr) {
151
+ throw new Error(`Failed to convert nested formula result to unit: ${unitErr instanceof Error ? unitErr.message : 'Unknown error'}`);
152
+ }
100
153
  scope[variable] = resultInUnit;
101
154
  }
102
155
  }
103
- // Evaluate the formula expression
104
- const compiled = compile(currentExpression);
105
- const result = compiled.evaluate(scope);
106
- const asUnit = mathUnit(result, normalizedUnit);
156
+ // Evaluate the formula expression with error handling for math errors
157
+ let compiled;
158
+ try {
159
+ compiled = compile(currentExpression);
160
+ }
161
+ catch (compileErr) {
162
+ throw new Error(`Failed to compile formula expression: ${compileErr instanceof Error ? compileErr.message : 'Unknown error'}`);
163
+ }
164
+ let result;
165
+ try {
166
+ result = compiled.evaluate(scope);
167
+ }
168
+ catch (evalErr) {
169
+ // Handle divide by zero and other math errors
170
+ const errorMessage = evalErr instanceof Error ? evalErr.message : String(evalErr);
171
+ if (errorMessage.includes('divide') ||
172
+ errorMessage.includes('division') ||
173
+ errorMessage.includes('/') ||
174
+ errorMessage.includes('Division by zero') ||
175
+ errorMessage.includes('Cannot divide by zero')) {
176
+ throw new Error(`Division by zero in formula: ${formulaId}`);
177
+ }
178
+ // Re-throw other evaluation errors
179
+ throw new Error(`Failed to evaluate formula: ${errorMessage}`);
180
+ }
181
+ // Check for invalid results (Infinity, NaN)
182
+ if (Number.isNaN(result)) {
183
+ throw new Error(`Formula result is NaN: ${formulaId}`);
184
+ }
185
+ if (!Number.isFinite(result)) {
186
+ throw new Error(`Formula result is Infinity: ${formulaId}`);
187
+ }
188
+ let asUnit;
189
+ try {
190
+ asUnit = mathUnit(result, normalizedUnit);
191
+ }
192
+ catch (unitErr) {
193
+ throw new Error(`Failed to convert result to unit: ${unitErr instanceof Error ? unitErr.message : 'Unknown error'}`);
194
+ }
107
195
  if (!asUnit.equalBase(mathUnit('1 um'))) {
108
196
  throw new Error(`Incompatible unit: ${asUnit.formatUnits()} is not compatible with ${normalizedUnit}`);
109
197
  }
110
198
  const finalResult = Math.round(asUnit.toNumber('um'));
199
+ // Check if final result is valid
200
+ if (!Number.isFinite(finalResult)) {
201
+ throw new Error(`Formula result is not a finite number: ${formulaId}`);
202
+ }
111
203
  // Cache the result
112
204
  cache.set(cacheKey, finalResult);
113
205
  return finalResult;
114
206
  }
207
+ catch (err) {
208
+ // Re-throw the error so it can be caught by the outer try-catch
209
+ throw err;
210
+ }
115
211
  finally {
116
212
  evaluationStack.delete(formulaId);
117
213
  }
@@ -32,24 +32,25 @@ export interface Face {
32
32
  measurementIds?: string[];
33
33
  };
34
34
  }
35
+ export interface BackgroundImage {
36
+ id: string;
37
+ fileId: string;
38
+ opacity: number;
39
+ centerWorld: {
40
+ x: number;
41
+ y: number;
42
+ };
43
+ pixelSizeWorld: number;
44
+ widthPx: number;
45
+ heightPx: number;
46
+ rotationRad: number;
47
+ }
35
48
  export interface Layout {
36
49
  id: string;
37
50
  name?: string;
38
51
  points: Record<string, Point>;
39
52
  edges: Record<string, Edge>;
40
53
  faces: Record<string, Face>;
41
- backgroundImage?: {
42
- fileId: string;
43
- opacity: number;
44
- centerWorld: {
45
- x: number;
46
- y: number;
47
- };
48
- pixelSizeWorld: number;
49
- widthPx: number;
50
- heightPx: number;
51
- rotationRad: number;
52
- };
53
54
  metadata?: {
54
55
  projectId?: string;
55
56
  jobId?: string;
@@ -1 +1,2 @@
1
1
  export {};
2
+ // BackgroundImage is stored as a subcollection: layoutGroups/{groupId}/backgroundImages/{imageId}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reekon-tools/boldr-utils",
3
- "version": "1.4.13",
3
+ "version": "1.4.15",
4
4
  "description": "Shared utilities for formulas and measurement conversion used in Reekon apps",
5
5
  "author": "REEKON Tools",
6
6
  "license": "MIT",