@reekon-tools/boldr-utils 1.4.12 → 1.4.14

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.
@@ -29,16 +29,22 @@ 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);
32
33
  return { id: mapping, type: 'measurement' };
33
34
  }
34
35
  // New format: ensure type defaults to 'measurement' and handle 'column' as 'measurement'
35
36
  const normalizedType = mapping.type === 'column' ? 'measurement' : mapping.type || 'measurement';
37
+ console.log('šŸ”§ Normalizing mapping:', mapping, '→', {
38
+ id: mapping.id,
39
+ type: normalizedType,
40
+ });
36
41
  return { id: mapping.id, type: normalizedType };
37
42
  }
38
43
  // Unified formula evaluation function
39
44
  export function evaluateFormula({ expression, mappings, valueMap, unit, formulas = [], scope, }) {
40
45
  // Legacy mode: if scope is provided, use it directly
41
46
  if (scope) {
47
+ console.log('šŸ“œ Using legacy scope mode');
42
48
  try {
43
49
  const normalizedUnit = normalizeUnitForMathJS(unit);
44
50
  const compiled = compile(expression);
@@ -62,6 +68,9 @@ export function evaluateFormula({ expression, mappings, valueMap, unit, formulas
62
68
  const evaluationStack = new Set(); // For circular dependency detection
63
69
  const cache = new Map(); // Local cache for this evaluation session
64
70
  function evaluateNestedFormula(formulaId, currentExpression, currentMappings) {
71
+ console.log(`šŸ” Evaluating nested formula: ${formulaId}`);
72
+ console.log(`šŸ“ Expression: "${currentExpression}"`);
73
+ console.log('šŸ—ŗļø Current mappings:', currentMappings);
65
74
  // Check for circular dependency
66
75
  if (evaluationStack.has(formulaId)) {
67
76
  throw new Error(`Circular dependency detected involving formula: ${formulaId}`);
@@ -69,26 +78,36 @@ export function evaluateFormula({ expression, mappings, valueMap, unit, formulas
69
78
  // Check cache first
70
79
  const cacheKey = `${formulaId}_${unit}`;
71
80
  if (cache.has(cacheKey)) {
81
+ console.log(`šŸ’¾ Using cached result for ${formulaId}`);
72
82
  return cache.get(cacheKey);
73
83
  }
74
84
  evaluationStack.add(formulaId);
75
85
  try {
76
86
  const scope = {};
77
87
  const normalizedUnit = normalizeUnitForMathJS(unit);
88
+ console.log(`šŸ”„ Converting to unit: ${unit} → ${normalizedUnit}`);
78
89
  // Build scope by resolving each variable
79
90
  for (const [variable, rawMapping] of Object.entries(currentMappings)) {
91
+ console.log(`\nšŸ”§ Processing variable "${variable}":`, rawMapping);
80
92
  const mapping = normalizeMapping(rawMapping);
93
+ console.log(`āœ… Normalized mapping:`, mapping);
81
94
  if (mapping.type === 'measurement') {
82
95
  // Handle measurement/column reference
96
+ console.log(`šŸ“Š Looking up measurement ID "${mapping.id}" in valueMap`);
83
97
  const micrometers = valueMap[mapping.id] ?? 0;
98
+ console.log(`šŸ“ˆ Found value: ${micrometers} micrometers`);
84
99
  if (micrometers === 0) {
85
100
  console.warn(`āš ļø Zero or missing value for mapping ID "${mapping.id}"`);
101
+ console.log('šŸ—‚ļø Available valueMap keys:', Object.keys(valueMap));
86
102
  }
87
- const valueInUnit = micrometers;
103
+ const valueInUnit = mathUnit(micrometers, 'um').toNumber(normalizedUnit);
104
+ console.log(`šŸ”¢ Converted to ${normalizedUnit}: ${valueInUnit}`);
88
105
  scope[variable] = valueInUnit;
106
+ console.log(`āœ… Set scope["${variable}"] = ${valueInUnit}`);
89
107
  }
90
108
  else if (mapping.type === 'formula') {
91
109
  // Handle formula reference - recursively evaluate
110
+ console.log(`šŸ”„ Recursively evaluating formula "${mapping.id}"`);
92
111
  const referencedFormula = formulas.find((f) => f.id === mapping.id);
93
112
  if (!referencedFormula) {
94
113
  throw new Error(`Referenced formula not found: ${mapping.id}`);
@@ -97,17 +116,25 @@ export function evaluateFormula({ expression, mappings, valueMap, unit, formulas
97
116
  const nestedResult = evaluateNestedFormula(referencedFormula.id, referencedFormula.expression, referencedFormula.variableToColumnMap);
98
117
  // Convert result to current unit
99
118
  const resultInUnit = mathUnit(nestedResult, 'um').toNumber(normalizedUnit);
119
+ console.log(`šŸ”¢ Nested formula result in ${normalizedUnit}: ${resultInUnit}`);
100
120
  scope[variable] = resultInUnit;
121
+ console.log(`āœ… Set scope["${variable}"] = ${resultInUnit} (from formula)`);
101
122
  }
102
123
  }
124
+ console.log('\nšŸŽÆ Final scope built:', scope);
103
125
  // Evaluate the formula expression
126
+ console.log(`šŸ“Š Compiling expression: "${currentExpression}"`);
104
127
  const compiled = compile(currentExpression);
128
+ console.log('🧮 Evaluating with scope:', scope);
105
129
  const result = compiled.evaluate(scope);
130
+ console.log('šŸ“‹ Raw evaluation result:', result, typeof result);
106
131
  const asUnit = mathUnit(result, normalizedUnit);
132
+ console.log('šŸ“ As unit object:', asUnit.toString());
107
133
  if (!asUnit.equalBase(mathUnit('1 um'))) {
108
134
  throw new Error(`Incompatible unit: ${asUnit.formatUnits()} is not compatible with ${normalizedUnit}`);
109
135
  }
110
136
  const finalResult = Math.round(asUnit.toNumber('um'));
137
+ console.log(`šŸŽÆ Final result: ${finalResult} micrometers`);
111
138
  // Cache the result
112
139
  cache.set(cacheKey, finalResult);
113
140
  return finalResult;
@@ -118,6 +145,7 @@ export function evaluateFormula({ expression, mappings, valueMap, unit, formulas
118
145
  }
119
146
  try {
120
147
  const result = evaluateNestedFormula('root', expression, mappings);
148
+ console.log(`šŸŽ‰ Formula evaluation completed successfully: ${result}`);
121
149
  return result;
122
150
  }
123
151
  catch (err) {
@@ -128,20 +156,25 @@ export function evaluateFormula({ expression, mappings, valueMap, unit, formulas
128
156
  // Legacy createFormulaScope function for backward compatibility
129
157
  export function createFormulaScope({ mappings, valueMap, unit, }) {
130
158
  const scope = {};
159
+ const normalizedUnit = normalizeUnitForMathJS(unit);
131
160
  for (const [variable, columnId] of Object.entries(mappings)) {
132
161
  const micrometers = valueMap[columnId] ?? 0;
133
- scope[variable] = micrometers;
162
+ // Convert using math.js directly
163
+ const valueInUnit = mathUnit(micrometers, 'um').toNumber(normalizedUnit);
164
+ scope[variable] = valueInUnit;
134
165
  }
135
166
  return scope;
136
167
  }
137
168
  // Enhanced createFormulaScope for new mapping structure
138
169
  export function createEnhancedFormulaScope({ mappings, valueMap, unit, formulas = [], }) {
139
170
  const scope = {};
171
+ const normalizedUnit = normalizeUnitForMathJS(unit);
140
172
  for (const [variable, rawMapping] of Object.entries(mappings)) {
141
173
  const mapping = normalizeMapping(rawMapping);
142
174
  if (mapping.type === 'measurement') {
143
175
  const micrometers = valueMap[mapping.id] ?? 0;
144
- scope[variable] = micrometers;
176
+ const valueInUnit = mathUnit(micrometers, 'um').toNumber(normalizedUnit);
177
+ scope[variable] = valueInUnit;
145
178
  }
146
179
  else if (mapping.type === 'formula') {
147
180
  // Find and evaluate the referenced formula
@@ -155,7 +188,8 @@ export function createEnhancedFormulaScope({ mappings, valueMap, unit, formulas
155
188
  formulas,
156
189
  });
157
190
  if (typeof result === 'number') {
158
- scope[variable] = result;
191
+ const valueInUnit = mathUnit(result, 'um').toNumber(normalizedUnit);
192
+ scope[variable] = valueInUnit;
159
193
  }
160
194
  else {
161
195
  scope[variable] = 0; // Error case
package/dist/index.d.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  export { evaluateFormula, createFormulaScope, createEnhancedFormulaScope, clearFormulaCache, type EnhancedMapping, type FormulaDefinition, type FormulaEvaluationOptions, } from './formulas/evaluateFormula.js';
2
- export { calculateFormula } from './formulas/calculateFormula.js';
3
2
  export { convertMicrometers } from './utils/micrometersToUnit.js';
4
3
  export { parseMeasurement } from './utils/parseMeasurement.js';
5
4
  export { useParseMeasurement } from './hooks/useParseMeasurement.js';
package/dist/index.js CHANGED
@@ -1,5 +1,4 @@
1
1
  export { evaluateFormula, createFormulaScope, createEnhancedFormulaScope, clearFormulaCache, } from './formulas/evaluateFormula.js';
2
- export { calculateFormula } from './formulas/calculateFormula.js';
3
2
  export { convertMicrometers } from './utils/micrometersToUnit.js';
4
3
  export { parseMeasurement } from './utils/parseMeasurement.js';
5
4
  export { useParseMeasurement } from './hooks/useParseMeasurement.js';
@@ -5,11 +5,9 @@ interface Timestamps {
5
5
  createdAt: Date;
6
6
  }
7
7
  interface CreatedBy {
8
- createdBy: {
9
- firstName: string;
10
- lastName: string;
11
- userId: string;
12
- };
8
+ firstName: string;
9
+ lastName: string;
10
+ userId: string;
13
11
  }
14
12
  export interface Organization extends FirestoreDoc, Timestamps {
15
13
  name: string;
@@ -64,20 +62,13 @@ export interface Project extends FirestoreDoc, Timestamps {
64
62
  city: string;
65
63
  zipCode: string;
66
64
  state: string;
67
- collectionId: string | null;
68
- index: number | null;
69
- }
70
- export declare enum TemplateType {
71
- Layout = "layout",
72
- Annotation = "annotation"
73
65
  }
74
- export interface Template extends Timestamps {
66
+ export interface Template {
75
67
  id: string;
76
68
  name: string;
77
69
  description: string;
78
70
  diagramFileId: string | null;
79
71
  diagramUrl: string;
80
- type?: TemplateType;
81
72
  tableConfig: ColumnConfig[];
82
73
  tolerances?: {
83
74
  [key: string]: {
@@ -87,49 +78,17 @@ export interface Template extends Timestamps {
87
78
  deviation: number;
88
79
  };
89
80
  };
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;
115
81
  }
116
82
  export declare enum FolderType {
117
83
  Project = "project",
118
- Job = "job",
119
- Template = "template"
84
+ Job = "job"
120
85
  }
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 {
86
+ export interface Folder extends FirestoreDoc {
127
87
  name: string;
128
88
  index: number;
129
89
  parentFolderId?: string | null;
130
90
  projectId: string | null;
131
91
  type: FolderType;
132
- isPublic?: boolean;
133
92
  }
134
93
  export declare enum JobType {
135
94
  DEFAULT = "default",
@@ -140,8 +99,7 @@ export interface Job extends FirestoreDoc, Timestamps {
140
99
  folderId: string;
141
100
  progress: number;
142
101
  projectId: string;
143
- totalTasks: number;
144
- lastAccessed: Date;
102
+ totalTasks: string;
145
103
  toleranceConfig?: {
146
104
  thresholds: {
147
105
  id: string;
@@ -152,10 +110,8 @@ export interface Job extends FirestoreDoc, Timestamps {
152
110
  };
153
111
  areaMapFileId?: string;
154
112
  type?: JobType;
155
- address?: string;
156
- description?: string;
157
113
  }
158
- export interface Section extends Timestamps {
114
+ export interface Section {
159
115
  id: string;
160
116
  name: string;
161
117
  tableConfig: ColumnConfig[];
@@ -184,12 +140,6 @@ export interface Group extends FirestoreDoc, Timestamps {
184
140
  formula?: any;
185
141
  isCompleted?: boolean;
186
142
  type?: string;
187
- details?: {
188
- material: string;
189
- finish: string;
190
- finishDate: string;
191
- };
192
- path?: string;
193
143
  }
194
144
  export declare enum ColumnType {
195
145
  Text = "text",
@@ -205,8 +155,7 @@ export declare enum ColumnType {
205
155
  export interface Formula extends FirestoreDoc, Timestamps {
206
156
  expression: string;
207
157
  name: string;
208
- variables: string[];
209
- variableToColumnMap: Record<string, any>;
158
+ varaibles: string[];
210
159
  }
211
160
  export interface ColumnConfig {
212
161
  id: string;
@@ -217,7 +166,6 @@ export interface ColumnConfig {
217
166
  withTolerance?: boolean;
218
167
  options?: string[];
219
168
  conversions?: Conversion[];
220
- size?: number;
221
169
  }
222
170
  export interface Conversion {
223
171
  label: string;
@@ -259,7 +207,6 @@ export declare enum Units {
259
207
  FeetInchesFractional = "ft_in_frac"
260
208
  }
261
209
  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";
263
210
  export declare enum FractionalTolerance {
264
211
  Fourth = "4",
265
212
  Eighth = "8",
@@ -10,21 +10,10 @@ 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 = {}));
23
13
  export var FolderType;
24
14
  (function (FolderType) {
25
15
  FolderType["Project"] = "project";
26
16
  FolderType["Job"] = "job";
27
- FolderType["Template"] = "template";
28
17
  })(FolderType || (FolderType = {}));
29
18
  export var JobType;
30
19
  (function (JobType) {
@@ -81,28 +70,6 @@ export const convertUnitsToReadable = (targetUnit) => {
81
70
  return null;
82
71
  }
83
72
  };
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
- };
106
73
  export var FractionalTolerance;
107
74
  (function (FractionalTolerance) {
108
75
  FractionalTolerance["Fourth"] = "4";
@@ -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}
@@ -1,5 +1,5 @@
1
1
  import { DecimalTolerance, FractionalTolerance, Units } from '../types/firestore.js';
2
- export declare const convertMicrometers: (micrometers: number | null | undefined, unit: Units, fractionalTolerance: FractionalTolerance, decimalTolerance: DecimalTolerance) => {
2
+ export declare const convertMicrometers: (micrometers: number, unit: Units, fractionalTolerance: FractionalTolerance, decimalTolerance: DecimalTolerance) => {
3
3
  value: string;
4
- unit: string;
4
+ unit: string | null;
5
5
  };
@@ -2,84 +2,75 @@ 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
- 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
- }
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}`;
31
20
  }
32
21
  else {
33
- value = inches.toFixed(decimalTolerance.length - 2);
22
+ value =
23
+ numerator === 0
24
+ ? `${whole}`
25
+ : `${whole} ${numerator}/${denominator}`;
34
26
  }
35
- break;
36
27
  }
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}"`;
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}"`;
63
48
  }
64
49
  else {
65
- value = feet.toFixed(decimalTolerance.length - 2);
50
+ value =
51
+ numerator === 0
52
+ ? `${wholeFeet}' ${wholeInches}"`
53
+ : `${wholeFeet}' ${wholeInches} ${numerator}/${denominator}"`;
66
54
  }
67
- break;
68
55
  }
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;
56
+ else if (unit === Units.FeetInchesDecimal) {
57
+ const inches = (fractionalFeet * 12).toFixed(decimalTolerance.length - 2);
58
+ value = `${wholeFeet}' ${inches}"`;
75
59
  }
76
- default:
77
- throw new Error('Unsupported unit');
60
+ else {
61
+ value = feet.toFixed(decimalTolerance.length - 2);
62
+ }
63
+ break;
78
64
  }
79
- return { value, unit: displayUnit };
80
- }
81
- catch (err) {
82
- console.warn('Error converting micrometers:', err);
83
- return { value: 'NaN', unit: '' };
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;
71
+ }
72
+ default:
73
+ throw new Error('Unsupported unit');
84
74
  }
75
+ return { value, unit: displayUnit };
85
76
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reekon-tools/boldr-utils",
3
- "version": "1.4.12",
3
+ "version": "1.4.14",
4
4
  "description": "Shared utilities for formulas and measurement conversion used in Reekon apps",
5
5
  "author": "REEKON Tools",
6
6
  "license": "MIT",
@@ -1,2 +0,0 @@
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;
@@ -1,114 +0,0 @@
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
- console.log('valueMap', valueMap);
66
- // Convert formulas to the expected FormulaDefinition format
67
- const formulaDefinitions = formulas
68
- .filter((f) => f.variableToColumnMap) // Only include formulas with new schema
69
- .map((f) => {
70
- const mappings = {};
71
- // Convert Firestore Map to plain object if necessary
72
- let fVariableToColumnMap = {};
73
- if (f.variableToColumnMap instanceof Map) {
74
- fVariableToColumnMap = Object.fromEntries(f.variableToColumnMap);
75
- }
76
- else if (typeof f.variableToColumnMap === 'object') {
77
- fVariableToColumnMap = f.variableToColumnMap;
78
- }
79
- for (const [variable, mapping] of Object.entries(fVariableToColumnMap)) {
80
- if (typeof mapping === 'string') {
81
- // Handle transition period - old format in new structure
82
- mappings[variable] = { id: mapping, type: 'column' };
83
- }
84
- else {
85
- // New format: { id: string; type: 'column' | 'formula' }
86
- mappings[variable] = mapping;
87
- }
88
- }
89
- return {
90
- id: f.id,
91
- name: f.name,
92
- expression: f.expression,
93
- variableToColumnMap: mappings,
94
- };
95
- });
96
- // Convert the current formula's mappings
97
- const currentMappings = {};
98
- for (const [variable, mapping] of Object.entries(variableToColumnMap)) {
99
- if (typeof mapping === 'string') {
100
- currentMappings[variable] = { id: mapping, type: 'column' };
101
- }
102
- else {
103
- currentMappings[variable] = mapping;
104
- }
105
- }
106
- const result = evaluateFormula({
107
- expression: formula.expression,
108
- mappings: currentMappings,
109
- valueMap: valueMap,
110
- unit: unit,
111
- formulas: formulaDefinitions,
112
- });
113
- return result;
114
- };