@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.
- package/dist/formulas/evaluateFormula.js +38 -4
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/types/firestore.d.ts +9 -62
- package/dist/types/firestore.js +0 -33
- package/dist/types/layout.d.ts +13 -12
- package/dist/types/layout.js +1 -0
- package/dist/utils/micrometersToUnit.d.ts +2 -2
- package/dist/utils/micrometersToUnit.js +60 -69
- package/package.json +1 -1
- package/dist/formulas/calculateFormula.d.ts +0 -2
- package/dist/formulas/calculateFormula.js +0 -114
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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
|
|
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
|
|
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:
|
|
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
|
|
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
|
-
|
|
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",
|
package/dist/types/firestore.js
CHANGED
|
@@ -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";
|
package/dist/types/layout.d.ts
CHANGED
|
@@ -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;
|
package/dist/types/layout.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DecimalTolerance, FractionalTolerance, Units } from '../types/firestore.js';
|
|
2
|
-
export declare const convertMicrometers: (micrometers: number
|
|
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
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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 =
|
|
22
|
+
value =
|
|
23
|
+
numerator === 0
|
|
24
|
+
? `${whole}`
|
|
25
|
+
: `${whole} ${numerator}/${denominator}`;
|
|
34
26
|
}
|
|
35
|
-
break;
|
|
36
27
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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 =
|
|
50
|
+
value =
|
|
51
|
+
numerator === 0
|
|
52
|
+
? `${wholeFeet}' ${wholeInches}"`
|
|
53
|
+
: `${wholeFeet}' ${wholeInches} ${numerator}/${denominator}"`;
|
|
66
54
|
}
|
|
67
|
-
break;
|
|
68
55
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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
|
-
|
|
77
|
-
|
|
60
|
+
else {
|
|
61
|
+
value = feet.toFixed(decimalTolerance.length - 2);
|
|
62
|
+
}
|
|
63
|
+
break;
|
|
78
64
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
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,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
|
-
};
|