@reekon-tools/boldr-utils 1.4.14 → 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.
@@ -0,0 +1,2 @@
1
+ import { ColumnConfig, DecimalTolerance, FractionalTolerance, Formula, Measurement, Units } from '../types/firestore.js';
2
+ export declare const calculateFormula: (formula: Formula, formulas: Formula[], columns: Record<string, string>, tableConfig: ColumnConfig[], measurements: Measurement[], unit: Units, fractionalTolerance: FractionalTolerance, decimalTolerance: DecimalTolerance) => string | number | null;
@@ -0,0 +1,113 @@
1
+ import { ColumnType, } from '../types/firestore.js';
2
+ import { evaluateFormula } from './evaluateFormula.js';
3
+ import { convertMicrometers } from '../utils/micrometersToUnit.js';
4
+ function parseMixedNumber(str) {
5
+ const parts = str.trim().split(' ');
6
+ let whole = 0;
7
+ let fraction = 0;
8
+ if (parts.length === 2) {
9
+ whole = parseFloat(parts[0]);
10
+ const [num, den] = parts[1].split('/').map(Number);
11
+ fraction = num / den;
12
+ }
13
+ else if (parts[0].includes('/')) {
14
+ const [num, den] = parts[0].split('/').map(Number);
15
+ fraction = num / den;
16
+ }
17
+ else {
18
+ whole = parseFloat(parts[0]);
19
+ }
20
+ return whole + fraction;
21
+ }
22
+ export const calculateFormula = (formula, formulas, columns, tableConfig, measurements, unit, fractionalTolerance, decimalTolerance) => {
23
+ // Convert Firestore Map to plain object if necessary
24
+ let variableToColumnMap = {};
25
+ if (formula.variableToColumnMap) {
26
+ if (formula.variableToColumnMap instanceof Map) {
27
+ // Convert Firestore Map to plain object
28
+ variableToColumnMap = Object.fromEntries(formula.variableToColumnMap);
29
+ }
30
+ else if (typeof formula.variableToColumnMap === 'object') {
31
+ // Already a plain object
32
+ variableToColumnMap = formula.variableToColumnMap;
33
+ }
34
+ }
35
+ if (Object.keys(variableToColumnMap).length === 0) {
36
+ return null;
37
+ }
38
+ // Build valueMap from group.columns and measurementMap
39
+ const valueMap = {};
40
+ for (const [columnId, measurementId] of Object.entries(columns)) {
41
+ const column = tableConfig.find((c) => c.id === columnId);
42
+ if (!column)
43
+ continue;
44
+ if (column.type === ColumnType.Measurement) {
45
+ const measurement = measurements.find((m) => m.id === measurementId);
46
+ if (!measurement)
47
+ continue;
48
+ const { value, unit: displayUnit } = convertMicrometers(measurement.value, unit, fractionalTolerance, decimalTolerance);
49
+ valueMap[columnId] = parseMixedNumber(value);
50
+ }
51
+ else if (column.type === ColumnType.Angle) {
52
+ const measurement = measurements.find((m) => m.id === measurementId);
53
+ if (!measurement)
54
+ continue;
55
+ valueMap[columnId] = measurement.value;
56
+ }
57
+ else if (column.type === ColumnType.ConversionTable) {
58
+ const value = measurementId.split(':')[1];
59
+ valueMap[columnId] = parseFloat(value);
60
+ }
61
+ else if (column.type === ColumnType.Number) {
62
+ valueMap[columnId] = parseFloat(measurementId);
63
+ }
64
+ }
65
+ // Convert formulas to the expected FormulaDefinition format
66
+ const formulaDefinitions = formulas
67
+ .filter((f) => f.variableToColumnMap) // Only include formulas with new schema
68
+ .map((f) => {
69
+ const mappings = {};
70
+ // Convert Firestore Map to plain object if necessary
71
+ let fVariableToColumnMap = {};
72
+ if (f.variableToColumnMap instanceof Map) {
73
+ fVariableToColumnMap = Object.fromEntries(f.variableToColumnMap);
74
+ }
75
+ else if (typeof f.variableToColumnMap === 'object') {
76
+ fVariableToColumnMap = f.variableToColumnMap;
77
+ }
78
+ for (const [variable, mapping] of Object.entries(fVariableToColumnMap)) {
79
+ if (typeof mapping === 'string') {
80
+ // Handle transition period - old format in new structure
81
+ mappings[variable] = { id: mapping, type: 'column' };
82
+ }
83
+ else {
84
+ // New format: { id: string; type: 'column' | 'formula' }
85
+ mappings[variable] = mapping;
86
+ }
87
+ }
88
+ return {
89
+ id: f.id,
90
+ name: f.name,
91
+ expression: f.expression,
92
+ variableToColumnMap: mappings,
93
+ };
94
+ });
95
+ // Convert the current formula's mappings
96
+ const currentMappings = {};
97
+ for (const [variable, mapping] of Object.entries(variableToColumnMap)) {
98
+ if (typeof mapping === 'string') {
99
+ currentMappings[variable] = { id: mapping, type: 'column' };
100
+ }
101
+ else {
102
+ currentMappings[variable] = mapping;
103
+ }
104
+ }
105
+ const result = evaluateFormula({
106
+ expression: formula.expression,
107
+ mappings: currentMappings,
108
+ valueMap: valueMap,
109
+ unit: unit,
110
+ formulas: formulaDefinitions,
111
+ });
112
+ return result;
113
+ };
@@ -29,31 +29,72 @@ function normalizeUnitForMathJS(unit) {
29
29
  function normalizeMapping(mapping) {
30
30
  if (typeof mapping === 'string') {
31
31
  // Legacy format: just the ID
32
- console.log('🔧 Converting legacy string mapping:', mapping);
33
32
  return { id: mapping, type: 'measurement' };
34
33
  }
35
34
  // New format: ensure type defaults to 'measurement' and handle 'column' as 'measurement'
36
35
  const normalizedType = mapping.type === 'column' ? 'measurement' : mapping.type || 'measurement';
37
- console.log('🔧 Normalizing mapping:', mapping, '→', {
38
- id: mapping.id,
39
- type: normalizedType,
40
- });
41
36
  return { id: mapping.id, type: normalizedType };
42
37
  }
43
38
  // Unified formula evaluation function
44
39
  export function evaluateFormula({ expression, mappings, valueMap, unit, formulas = [], scope, }) {
45
40
  // Legacy mode: if scope is provided, use it directly
46
41
  if (scope) {
47
- console.log('📜 Using legacy scope mode');
48
42
  try {
49
43
  const normalizedUnit = normalizeUnitForMathJS(unit);
50
- const compiled = compile(expression);
51
- const result = compiled.evaluate(scope);
52
- 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
+ }
53
87
  if (!asUnit.equalBase(mathUnit('1 um'))) {
54
- 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;
55
90
  }
56
- 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;
57
98
  }
58
99
  catch (err) {
59
100
  console.error(`Failed to evaluate formula`, err);
@@ -68,9 +109,6 @@ export function evaluateFormula({ expression, mappings, valueMap, unit, formulas
68
109
  const evaluationStack = new Set(); // For circular dependency detection
69
110
  const cache = new Map(); // Local cache for this evaluation session
70
111
  function evaluateNestedFormula(formulaId, currentExpression, currentMappings) {
71
- console.log(`🔍 Evaluating nested formula: ${formulaId}`);
72
- console.log(`📝 Expression: "${currentExpression}"`);
73
- console.log('🗺️ Current mappings:', currentMappings);
74
112
  // Check for circular dependency
75
113
  if (evaluationStack.has(formulaId)) {
76
114
  throw new Error(`Circular dependency detected involving formula: ${formulaId}`);
@@ -78,74 +116,104 @@ export function evaluateFormula({ expression, mappings, valueMap, unit, formulas
78
116
  // Check cache first
79
117
  const cacheKey = `${formulaId}_${unit}`;
80
118
  if (cache.has(cacheKey)) {
81
- console.log(`💾 Using cached result for ${formulaId}`);
82
119
  return cache.get(cacheKey);
83
120
  }
84
121
  evaluationStack.add(formulaId);
85
122
  try {
86
123
  const scope = {};
87
124
  const normalizedUnit = normalizeUnitForMathJS(unit);
88
- console.log(`🔄 Converting to unit: ${unit} → ${normalizedUnit}`);
89
125
  // Build scope by resolving each variable
90
126
  for (const [variable, rawMapping] of Object.entries(currentMappings)) {
91
- console.log(`\n🔧 Processing variable "${variable}":`, rawMapping);
92
127
  const mapping = normalizeMapping(rawMapping);
93
- console.log(`✅ Normalized mapping:`, mapping);
94
128
  if (mapping.type === 'measurement') {
95
129
  // Handle measurement/column reference
96
- console.log(`📊 Looking up measurement ID "${mapping.id}" in valueMap`);
97
130
  const micrometers = valueMap[mapping.id] ?? 0;
98
- console.log(`📈 Found value: ${micrometers} micrometers`);
99
131
  if (micrometers === 0) {
100
132
  console.warn(`⚠️ Zero or missing value for mapping ID "${mapping.id}"`);
101
- console.log('🗂️ Available valueMap keys:', Object.keys(valueMap));
102
133
  }
103
- const valueInUnit = mathUnit(micrometers, 'um').toNumber(normalizedUnit);
104
- console.log(`🔢 Converted to ${normalizedUnit}: ${valueInUnit}`);
134
+ const valueInUnit = micrometers;
105
135
  scope[variable] = valueInUnit;
106
- console.log(`✅ Set scope["${variable}"] = ${valueInUnit}`);
107
136
  }
108
137
  else if (mapping.type === 'formula') {
109
138
  // Handle formula reference - recursively evaluate
110
- console.log(`🔄 Recursively evaluating formula "${mapping.id}"`);
111
139
  const referencedFormula = formulas.find((f) => f.id === mapping.id);
112
140
  if (!referencedFormula) {
113
141
  throw new Error(`Referenced formula not found: ${mapping.id}`);
114
142
  }
115
143
  // Recursively evaluate the referenced formula
116
144
  const nestedResult = evaluateNestedFormula(referencedFormula.id, referencedFormula.expression, referencedFormula.variableToColumnMap);
117
- // Convert result to current unit
118
- const resultInUnit = mathUnit(nestedResult, 'um').toNumber(normalizedUnit);
119
- console.log(`🔢 Nested formula result in ${normalizedUnit}: ${resultInUnit}`);
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
+ }
120
153
  scope[variable] = resultInUnit;
121
- console.log(`✅ Set scope["${variable}"] = ${resultInUnit} (from formula)`);
122
154
  }
123
155
  }
124
- console.log('\n🎯 Final scope built:', scope);
125
- // Evaluate the formula expression
126
- console.log(`📊 Compiling expression: "${currentExpression}"`);
127
- const compiled = compile(currentExpression);
128
- console.log('🧮 Evaluating with scope:', scope);
129
- const result = compiled.evaluate(scope);
130
- console.log('📋 Raw evaluation result:', result, typeof result);
131
- const asUnit = mathUnit(result, normalizedUnit);
132
- console.log('📏 As unit object:', asUnit.toString());
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
+ }
133
195
  if (!asUnit.equalBase(mathUnit('1 um'))) {
134
196
  throw new Error(`Incompatible unit: ${asUnit.formatUnits()} is not compatible with ${normalizedUnit}`);
135
197
  }
136
198
  const finalResult = Math.round(asUnit.toNumber('um'));
137
- console.log(`🎯 Final result: ${finalResult} micrometers`);
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
+ }
138
203
  // Cache the result
139
204
  cache.set(cacheKey, finalResult);
140
205
  return finalResult;
141
206
  }
207
+ catch (err) {
208
+ // Re-throw the error so it can be caught by the outer try-catch
209
+ throw err;
210
+ }
142
211
  finally {
143
212
  evaluationStack.delete(formulaId);
144
213
  }
145
214
  }
146
215
  try {
147
216
  const result = evaluateNestedFormula('root', expression, mappings);
148
- console.log(`🎉 Formula evaluation completed successfully: ${result}`);
149
217
  return result;
150
218
  }
151
219
  catch (err) {
@@ -156,25 +224,20 @@ export function evaluateFormula({ expression, mappings, valueMap, unit, formulas
156
224
  // Legacy createFormulaScope function for backward compatibility
157
225
  export function createFormulaScope({ mappings, valueMap, unit, }) {
158
226
  const scope = {};
159
- const normalizedUnit = normalizeUnitForMathJS(unit);
160
227
  for (const [variable, columnId] of Object.entries(mappings)) {
161
228
  const micrometers = valueMap[columnId] ?? 0;
162
- // Convert using math.js directly
163
- const valueInUnit = mathUnit(micrometers, 'um').toNumber(normalizedUnit);
164
- scope[variable] = valueInUnit;
229
+ scope[variable] = micrometers;
165
230
  }
166
231
  return scope;
167
232
  }
168
233
  // Enhanced createFormulaScope for new mapping structure
169
234
  export function createEnhancedFormulaScope({ mappings, valueMap, unit, formulas = [], }) {
170
235
  const scope = {};
171
- const normalizedUnit = normalizeUnitForMathJS(unit);
172
236
  for (const [variable, rawMapping] of Object.entries(mappings)) {
173
237
  const mapping = normalizeMapping(rawMapping);
174
238
  if (mapping.type === 'measurement') {
175
239
  const micrometers = valueMap[mapping.id] ?? 0;
176
- const valueInUnit = mathUnit(micrometers, 'um').toNumber(normalizedUnit);
177
- scope[variable] = valueInUnit;
240
+ scope[variable] = micrometers;
178
241
  }
179
242
  else if (mapping.type === 'formula') {
180
243
  // Find and evaluate the referenced formula
@@ -188,8 +251,7 @@ export function createEnhancedFormulaScope({ mappings, valueMap, unit, formulas
188
251
  formulas,
189
252
  });
190
253
  if (typeof result === 'number') {
191
- const valueInUnit = mathUnit(result, 'um').toNumber(normalizedUnit);
192
- scope[variable] = valueInUnit;
254
+ scope[variable] = result;
193
255
  }
194
256
  else {
195
257
  scope[variable] = 0; // Error case
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export { evaluateFormula, createFormulaScope, createEnhancedFormulaScope, clearFormulaCache, type EnhancedMapping, type FormulaDefinition, type FormulaEvaluationOptions, } from './formulas/evaluateFormula.js';
2
+ export { calculateFormula } from './formulas/calculateFormula.js';
2
3
  export { convertMicrometers } from './utils/micrometersToUnit.js';
3
4
  export { parseMeasurement } from './utils/parseMeasurement.js';
4
5
  export { useParseMeasurement } from './hooks/useParseMeasurement.js';
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export { evaluateFormula, createFormulaScope, createEnhancedFormulaScope, clearFormulaCache, } from './formulas/evaluateFormula.js';
2
+ export { calculateFormula } from './formulas/calculateFormula.js';
2
3
  export { convertMicrometers } from './utils/micrometersToUnit.js';
3
4
  export { parseMeasurement } from './utils/parseMeasurement.js';
4
5
  export { useParseMeasurement } from './hooks/useParseMeasurement.js';
@@ -5,9 +5,11 @@ interface Timestamps {
5
5
  createdAt: Date;
6
6
  }
7
7
  interface CreatedBy {
8
- firstName: string;
9
- lastName: string;
10
- userId: string;
8
+ createdBy: {
9
+ firstName: string;
10
+ lastName: string;
11
+ userId: string;
12
+ };
11
13
  }
12
14
  export interface Organization extends FirestoreDoc, Timestamps {
13
15
  name: string;
@@ -62,13 +64,20 @@ export interface Project extends FirestoreDoc, Timestamps {
62
64
  city: string;
63
65
  zipCode: string;
64
66
  state: string;
67
+ collectionId: string | null;
68
+ index: number | null;
69
+ }
70
+ export declare enum TemplateType {
71
+ Layout = "layout",
72
+ Annotation = "annotation"
65
73
  }
66
- export interface Template {
74
+ export interface Template extends Timestamps {
67
75
  id: string;
68
76
  name: string;
69
77
  description: string;
70
78
  diagramFileId: string | null;
71
79
  diagramUrl: string;
80
+ type?: TemplateType;
72
81
  tableConfig: ColumnConfig[];
73
82
  tolerances?: {
74
83
  [key: string]: {
@@ -78,17 +87,49 @@ export interface Template {
78
87
  deviation: number;
79
88
  };
80
89
  };
90
+ isPublic: boolean;
91
+ orgId: string;
92
+ orgName: string;
93
+ parentFolderId?: string | null;
94
+ }
95
+ export interface SelectedTemplate extends FirestoreDoc {
96
+ count: number;
97
+ isPublic: boolean;
98
+ name: string;
99
+ groupType?: string;
100
+ }
101
+ export declare enum FileUploadType {
102
+ Annotation = "annotation",
103
+ Template = "template"
104
+ }
105
+ export interface FileUpload {
106
+ id: string;
107
+ name: string;
108
+ projectId: string;
109
+ jobId: string;
110
+ groupId: string;
111
+ type: FileUploadType;
112
+ folderPath: string;
113
+ thumbnailUrl: string | null;
114
+ fileType: string | null;
81
115
  }
82
116
  export declare enum FolderType {
83
117
  Project = "project",
84
- Job = "job"
118
+ Job = "job",
119
+ Template = "template"
85
120
  }
86
- export interface Folder extends FirestoreDoc {
121
+ export interface ProjectFolder extends FirestoreDoc, Timestamps {
122
+ name: string;
123
+ parentFolderId: string | null;
124
+ projectId: string;
125
+ }
126
+ export interface Folder extends FirestoreDoc, Timestamps {
87
127
  name: string;
88
128
  index: number;
89
129
  parentFolderId?: string | null;
90
130
  projectId: string | null;
91
131
  type: FolderType;
132
+ isPublic?: boolean;
92
133
  }
93
134
  export declare enum JobType {
94
135
  DEFAULT = "default",
@@ -99,7 +140,8 @@ export interface Job extends FirestoreDoc, Timestamps {
99
140
  folderId: string;
100
141
  progress: number;
101
142
  projectId: string;
102
- totalTasks: string;
143
+ totalTasks: number;
144
+ lastAccessed: Date;
103
145
  toleranceConfig?: {
104
146
  thresholds: {
105
147
  id: string;
@@ -110,8 +152,10 @@ export interface Job extends FirestoreDoc, Timestamps {
110
152
  };
111
153
  areaMapFileId?: string;
112
154
  type?: JobType;
155
+ address?: string;
156
+ description?: string;
113
157
  }
114
- export interface Section {
158
+ export interface Section extends Timestamps {
115
159
  id: string;
116
160
  name: string;
117
161
  tableConfig: ColumnConfig[];
@@ -140,6 +184,12 @@ export interface Group extends FirestoreDoc, Timestamps {
140
184
  formula?: any;
141
185
  isCompleted?: boolean;
142
186
  type?: string;
187
+ details?: {
188
+ material: string;
189
+ finish: string;
190
+ finishDate: string;
191
+ };
192
+ path?: string;
143
193
  }
144
194
  export declare enum ColumnType {
145
195
  Text = "text",
@@ -155,7 +205,8 @@ export declare enum ColumnType {
155
205
  export interface Formula extends FirestoreDoc, Timestamps {
156
206
  expression: string;
157
207
  name: string;
158
- varaibles: string[];
208
+ variables: string[];
209
+ variableToColumnMap: Record<string, any>;
159
210
  }
160
211
  export interface ColumnConfig {
161
212
  id: string;
@@ -166,6 +217,7 @@ export interface ColumnConfig {
166
217
  withTolerance?: boolean;
167
218
  options?: string[];
168
219
  conversions?: Conversion[];
220
+ size?: number;
169
221
  }
170
222
  export interface Conversion {
171
223
  label: string;
@@ -207,6 +259,7 @@ export declare enum Units {
207
259
  FeetInchesFractional = "ft_in_frac"
208
260
  }
209
261
  export declare const convertUnitsToReadable: (targetUnit: Units) => "cm" | "mm" | "m" | "in" | "ft" | "in (fractional)" | "ft-in (decimal)" | "ft-in (fractional)" | null;
262
+ export declare const convertUnitsToReadableShort: (targetUnit: Units) => "cm" | "mm" | "m" | "in" | "ft" | "ft-in";
210
263
  export declare enum FractionalTolerance {
211
264
  Fourth = "4",
212
265
  Eighth = "8",
@@ -10,10 +10,21 @@ export var InvitationStatus;
10
10
  InvitationStatus["Pending"] = "pending";
11
11
  InvitationStatus["Accepted"] = "accepted";
12
12
  })(InvitationStatus || (InvitationStatus = {}));
13
+ export var TemplateType;
14
+ (function (TemplateType) {
15
+ TemplateType["Layout"] = "layout";
16
+ TemplateType["Annotation"] = "annotation";
17
+ })(TemplateType || (TemplateType = {}));
18
+ export var FileUploadType;
19
+ (function (FileUploadType) {
20
+ FileUploadType["Annotation"] = "annotation";
21
+ FileUploadType["Template"] = "template";
22
+ })(FileUploadType || (FileUploadType = {}));
13
23
  export var FolderType;
14
24
  (function (FolderType) {
15
25
  FolderType["Project"] = "project";
16
26
  FolderType["Job"] = "job";
27
+ FolderType["Template"] = "template";
17
28
  })(FolderType || (FolderType = {}));
18
29
  export var JobType;
19
30
  (function (JobType) {
@@ -70,6 +81,28 @@ export const convertUnitsToReadable = (targetUnit) => {
70
81
  return null;
71
82
  }
72
83
  };
84
+ export const convertUnitsToReadableShort = (targetUnit) => {
85
+ switch (targetUnit) {
86
+ case Units.Meters:
87
+ return 'm';
88
+ case Units.Millimeters:
89
+ return 'mm';
90
+ case Units.Centimeters:
91
+ return 'cm';
92
+ case Units.Feet:
93
+ return 'ft';
94
+ case Units.FractionalInches:
95
+ return 'in';
96
+ case Units.Inches:
97
+ return 'in';
98
+ case Units.FeetInchesDecimal:
99
+ return 'ft-in';
100
+ case Units.FeetInchesFractional:
101
+ return 'ft-in';
102
+ default:
103
+ return targetUnit;
104
+ }
105
+ };
73
106
  export var FractionalTolerance;
74
107
  (function (FractionalTolerance) {
75
108
  FractionalTolerance["Fourth"] = "4";
@@ -1,5 +1,5 @@
1
1
  import { DecimalTolerance, FractionalTolerance, Units } from '../types/firestore.js';
2
- export declare const convertMicrometers: (micrometers: number, unit: Units, fractionalTolerance: FractionalTolerance, decimalTolerance: DecimalTolerance) => {
2
+ export declare const convertMicrometers: (micrometers: number | null | undefined, unit: Units, fractionalTolerance: FractionalTolerance, decimalTolerance: DecimalTolerance) => {
3
3
  value: string;
4
- unit: string | null;
4
+ unit: string;
5
5
  };
@@ -2,75 +2,84 @@ import { Units, convertUnitsToReadable, } from '../types/firestore.js';
2
2
  import { create, all } from 'mathjs';
3
3
  const math = create(all);
4
4
  export const convertMicrometers = (micrometers, unit, fractionalTolerance, decimalTolerance) => {
5
- const converted = math.unit(micrometers, 'um');
6
- let value = 0;
7
- let displayUnit = '';
8
- switch (unit) {
9
- case Units.Inches:
10
- case Units.FractionalInches: {
11
- const inches = converted.toNumber('in');
12
- displayUnit = 'in';
13
- if (unit === Units.FractionalInches) {
14
- const denominator = parseInt(fractionalTolerance, 10);
15
- const whole = Math.floor(inches);
16
- const fractional = inches - whole;
17
- const numerator = Math.round(fractional * denominator);
18
- if (numerator === denominator) {
19
- value = `${whole + 1}`;
5
+ if (micrometers == null || isNaN(micrometers)) {
6
+ return { value: 'NaN', unit: '' };
7
+ }
8
+ try {
9
+ const converted = math.unit(micrometers, 'um');
10
+ let value = 0;
11
+ let displayUnit = '';
12
+ switch (unit) {
13
+ case Units.Inches:
14
+ case Units.FractionalInches: {
15
+ const inches = converted.toNumber('in');
16
+ displayUnit = 'in';
17
+ if (unit === Units.FractionalInches) {
18
+ const denominator = parseInt(fractionalTolerance, 10);
19
+ const whole = Math.floor(inches);
20
+ const fractional = inches - whole;
21
+ const numerator = Math.round(fractional * denominator);
22
+ if (numerator === denominator) {
23
+ value = `${whole + 1}`;
24
+ }
25
+ else {
26
+ value =
27
+ numerator === 0
28
+ ? `${whole}`
29
+ : `${whole} ${numerator}/${denominator}`;
30
+ }
20
31
  }
21
32
  else {
22
- value =
23
- numerator === 0
24
- ? `${whole}`
25
- : `${whole} ${numerator}/${denominator}`;
33
+ value = inches.toFixed(decimalTolerance.length - 2);
26
34
  }
35
+ break;
27
36
  }
28
- else {
29
- value = inches.toFixed(decimalTolerance.length - 2); // Match decimal places to tolerance
30
- }
31
- break;
32
- }
33
- case Units.Feet:
34
- case Units.FeetInchesFractional:
35
- case Units.FeetInchesDecimal: {
36
- const feet = converted.toNumber('ft');
37
- const wholeFeet = Math.floor(feet);
38
- const fractionalFeet = feet - wholeFeet;
39
- displayUnit = 'ft';
40
- if (unit === Units.FeetInchesFractional) {
41
- const inches = fractionalFeet * 12;
42
- const wholeInches = Math.floor(inches);
43
- const fractional = inches - wholeInches;
44
- const denominator = parseInt(fractionalTolerance, 10);
45
- const numerator = Math.round(fractional * denominator);
46
- if (numerator === denominator) {
47
- value = `${wholeFeet}' ${wholeInches + 1}"`;
37
+ case Units.Feet:
38
+ case Units.FeetInchesFractional:
39
+ case Units.FeetInchesDecimal: {
40
+ const feet = converted.toNumber('ft');
41
+ const wholeFeet = Math.floor(feet);
42
+ const fractionalFeet = feet - wholeFeet;
43
+ displayUnit = 'ft';
44
+ if (unit === Units.FeetInchesFractional) {
45
+ const inches = fractionalFeet * 12;
46
+ const wholeInches = Math.floor(inches);
47
+ const fractional = inches - wholeInches;
48
+ const denominator = parseInt(fractionalTolerance, 10);
49
+ const numerator = Math.round(fractional * denominator);
50
+ if (numerator === denominator) {
51
+ value = `${wholeFeet}' ${wholeInches + 1}"`;
52
+ }
53
+ else {
54
+ value =
55
+ numerator === 0
56
+ ? `${wholeFeet}' ${wholeInches}"`
57
+ : `${wholeFeet}' ${wholeInches} ${numerator}/${denominator}"`;
58
+ }
59
+ }
60
+ else if (unit === Units.FeetInchesDecimal) {
61
+ const inches = (fractionalFeet * 12).toFixed(decimalTolerance.length - 2);
62
+ value = `${wholeFeet}' ${inches}"`;
48
63
  }
49
64
  else {
50
- value =
51
- numerator === 0
52
- ? `${wholeFeet}' ${wholeInches}"`
53
- : `${wholeFeet}' ${wholeInches} ${numerator}/${denominator}"`;
65
+ value = feet.toFixed(decimalTolerance.length - 2);
54
66
  }
67
+ break;
55
68
  }
56
- else if (unit === Units.FeetInchesDecimal) {
57
- const inches = (fractionalFeet * 12).toFixed(decimalTolerance.length - 2);
58
- value = `${wholeFeet}' ${inches}"`;
69
+ case Units.Meters:
70
+ case Units.Centimeters:
71
+ case Units.Millimeters: {
72
+ displayUnit = convertUnitsToReadable(unit) ?? '';
73
+ value = converted.toNumber(unit).toFixed(decimalTolerance.length - 2);
74
+ break;
59
75
  }
60
- else {
61
- value = feet.toFixed(decimalTolerance.length - 2);
62
- }
63
- break;
64
- }
65
- case Units.Meters:
66
- case Units.Centimeters:
67
- case Units.Millimeters: {
68
- displayUnit = convertUnitsToReadable(unit);
69
- value = converted.toNumber(unit).toFixed(decimalTolerance.length - 2);
70
- break;
76
+ default:
77
+ throw new Error('Unsupported unit');
71
78
  }
72
- default:
73
- throw new Error('Unsupported unit');
79
+ return { value, unit: displayUnit };
80
+ }
81
+ catch (err) {
82
+ console.warn('Error converting micrometers:', err);
83
+ return { value: 'NaN', unit: '' };
74
84
  }
75
- return { value, unit: displayUnit };
76
85
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reekon-tools/boldr-utils",
3
- "version": "1.4.14",
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",