@reekon-tools/boldr-utils 1.4.10 → 1.4.12

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.
@@ -1,2 +1,2 @@
1
- import { Formula, Measurement, Units } from '../types/firestore.js';
2
- export declare const calculateFormula: (formula: Formula, formulas: Formula[], columns: Record<string, any>, measurements: Measurement[], unit: Units) => string | number | null;
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,5 +1,25 @@
1
+ import { ColumnType, } from '../types/firestore.js';
1
2
  import { evaluateFormula } from './evaluateFormula.js';
2
- export const calculateFormula = (formula, formulas, columns, measurements, unit) => {
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) => {
3
23
  // Convert Firestore Map to plain object if necessary
4
24
  let variableToColumnMap = {};
5
25
  if (formula.variableToColumnMap) {
@@ -17,19 +37,32 @@ export const calculateFormula = (formula, formulas, columns, measurements, unit)
17
37
  }
18
38
  // Build valueMap from group.columns and measurementMap
19
39
  const valueMap = {};
20
- // Map column IDs to their actual measurement values
21
40
  for (const [columnId, measurementId] of Object.entries(columns)) {
22
- const measurement = measurements.find((m) => m.id === measurementId);
23
- if (measurement?.value !== undefined) {
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;
24
55
  valueMap[columnId] = measurement.value;
25
56
  }
26
- else {
27
- const numericValue = typeof measurementId === 'number'
28
- ? measurementId
29
- : parseFloat(measurementId || '0');
30
- valueMap[columnId] = isNaN(numericValue) ? 0 : numericValue;
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);
31
63
  }
32
64
  }
65
+ console.log('valueMap', valueMap);
33
66
  // Convert formulas to the expected FormulaDefinition format
34
67
  const formulaDefinitions = formulas
35
68
  .filter((f) => f.variableToColumnMap) // Only include formulas with new schema
@@ -73,7 +106,7 @@ export const calculateFormula = (formula, formulas, columns, measurements, unit)
73
106
  const result = evaluateFormula({
74
107
  expression: formula.expression,
75
108
  mappings: currentMappings,
76
- valueMap,
109
+ valueMap: valueMap,
77
110
  unit: unit,
78
111
  formulas: formulaDefinitions,
79
112
  });
@@ -84,7 +84,7 @@ export function evaluateFormula({ expression, mappings, valueMap, unit, formulas
84
84
  if (micrometers === 0) {
85
85
  console.warn(`⚠️ Zero or missing value for mapping ID "${mapping.id}"`);
86
86
  }
87
- const valueInUnit = mathUnit(micrometers, 'um').toNumber(normalizedUnit);
87
+ const valueInUnit = micrometers;
88
88
  scope[variable] = valueInUnit;
89
89
  }
90
90
  else if (mapping.type === 'formula') {
@@ -128,25 +128,20 @@ export function evaluateFormula({ expression, mappings, valueMap, unit, formulas
128
128
  // Legacy createFormulaScope function for backward compatibility
129
129
  export function createFormulaScope({ mappings, valueMap, unit, }) {
130
130
  const scope = {};
131
- const normalizedUnit = normalizeUnitForMathJS(unit);
132
131
  for (const [variable, columnId] of Object.entries(mappings)) {
133
132
  const micrometers = valueMap[columnId] ?? 0;
134
- // Convert using math.js directly
135
- const valueInUnit = mathUnit(micrometers, 'um').toNumber(normalizedUnit);
136
- scope[variable] = valueInUnit;
133
+ scope[variable] = micrometers;
137
134
  }
138
135
  return scope;
139
136
  }
140
137
  // Enhanced createFormulaScope for new mapping structure
141
138
  export function createEnhancedFormulaScope({ mappings, valueMap, unit, formulas = [], }) {
142
139
  const scope = {};
143
- const normalizedUnit = normalizeUnitForMathJS(unit);
144
140
  for (const [variable, rawMapping] of Object.entries(mappings)) {
145
141
  const mapping = normalizeMapping(rawMapping);
146
142
  if (mapping.type === 'measurement') {
147
143
  const micrometers = valueMap[mapping.id] ?? 0;
148
- const valueInUnit = mathUnit(micrometers, 'um').toNumber(normalizedUnit);
149
- scope[variable] = valueInUnit;
144
+ scope[variable] = micrometers;
150
145
  }
151
146
  else if (mapping.type === 'formula') {
152
147
  // Find and evaluate the referenced formula
@@ -160,8 +155,7 @@ export function createEnhancedFormulaScope({ mappings, valueMap, unit, formulas
160
155
  formulas,
161
156
  });
162
157
  if (typeof result === 'number') {
163
- const valueInUnit = mathUnit(result, 'um').toNumber(normalizedUnit);
164
- scope[variable] = valueInUnit;
158
+ scope[variable] = result;
165
159
  }
166
160
  else {
167
161
  scope[variable] = 0; // Error case
@@ -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.10",
3
+ "version": "1.4.12",
4
4
  "description": "Shared utilities for formulas and measurement conversion used in Reekon apps",
5
5
  "author": "REEKON Tools",
6
6
  "license": "MIT",