@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,
|
|
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
|
-
|
|
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
|
|
23
|
-
if (
|
|
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
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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
|
-
|
|
61
|
-
|
|
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
|
-
|
|
73
|
-
|
|
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
|
};
|