@purveyors/cli 0.2.1 → 0.3.0

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.
Files changed (73) hide show
  1. package/dist/commands/catalog.d.ts +4 -56
  2. package/dist/commands/catalog.d.ts.map +1 -1
  3. package/dist/commands/catalog.js +14 -81
  4. package/dist/commands/catalog.js.map +1 -1
  5. package/dist/commands/inventory.d.ts +2 -25
  6. package/dist/commands/inventory.d.ts.map +1 -1
  7. package/dist/commands/inventory.js +47 -147
  8. package/dist/commands/inventory.js.map +1 -1
  9. package/dist/commands/roast.d.ts +2 -41
  10. package/dist/commands/roast.d.ts.map +1 -1
  11. package/dist/commands/roast.js +138 -125
  12. package/dist/commands/roast.js.map +1 -1
  13. package/dist/commands/sales.d.ts +2 -10
  14. package/dist/commands/sales.d.ts.map +1 -1
  15. package/dist/commands/sales.js +30 -109
  16. package/dist/commands/sales.js.map +1 -1
  17. package/dist/commands/tasting.d.ts +4 -38
  18. package/dist/commands/tasting.d.ts.map +1 -1
  19. package/dist/commands/tasting.js +18 -108
  20. package/dist/commands/tasting.js.map +1 -1
  21. package/dist/lib/artisan/db.d.ts +37 -0
  22. package/dist/lib/artisan/db.d.ts.map +1 -0
  23. package/dist/lib/artisan/db.js +51 -0
  24. package/dist/lib/artisan/db.js.map +1 -0
  25. package/dist/lib/artisan/import.d.ts +16 -0
  26. package/dist/lib/artisan/import.d.ts.map +1 -0
  27. package/dist/lib/artisan/import.js +447 -0
  28. package/dist/lib/artisan/import.js.map +1 -0
  29. package/dist/lib/artisan/index.d.ts +9 -0
  30. package/dist/lib/artisan/index.d.ts.map +1 -0
  31. package/dist/lib/artisan/index.js +7 -0
  32. package/dist/lib/artisan/index.js.map +1 -0
  33. package/dist/lib/artisan/parser.d.ts +19 -0
  34. package/dist/lib/artisan/parser.d.ts.map +1 -0
  35. package/dist/lib/artisan/parser.js +376 -0
  36. package/dist/lib/artisan/parser.js.map +1 -0
  37. package/dist/lib/artisan/temperature.d.ts +52 -0
  38. package/dist/lib/artisan/temperature.d.ts.map +1 -0
  39. package/dist/lib/artisan/temperature.js +101 -0
  40. package/dist/lib/artisan/temperature.js.map +1 -0
  41. package/dist/lib/artisan/types.d.ts +195 -0
  42. package/dist/lib/artisan/types.d.ts.map +1 -0
  43. package/dist/lib/artisan/types.js +35 -0
  44. package/dist/lib/artisan/types.js.map +1 -0
  45. package/dist/lib/artisan/validator.d.ts +14 -0
  46. package/dist/lib/artisan/validator.d.ts.map +1 -0
  47. package/dist/lib/artisan/validator.js +228 -0
  48. package/dist/lib/artisan/validator.js.map +1 -0
  49. package/dist/lib/catalog.d.ts +87 -0
  50. package/dist/lib/catalog.d.ts.map +1 -0
  51. package/dist/lib/catalog.js +111 -0
  52. package/dist/lib/catalog.js.map +1 -0
  53. package/dist/lib/index.d.ts +6 -0
  54. package/dist/lib/index.d.ts.map +1 -0
  55. package/dist/lib/index.js +11 -0
  56. package/dist/lib/index.js.map +1 -0
  57. package/dist/lib/inventory.d.ts +80 -0
  58. package/dist/lib/inventory.d.ts.map +1 -0
  59. package/dist/lib/inventory.js +205 -0
  60. package/dist/lib/inventory.js.map +1 -0
  61. package/dist/lib/roast.d.ts +127 -0
  62. package/dist/lib/roast.d.ts.map +1 -0
  63. package/dist/lib/roast.js +284 -0
  64. package/dist/lib/roast.js.map +1 -0
  65. package/dist/lib/sales.d.ts +53 -0
  66. package/dist/lib/sales.d.ts.map +1 -0
  67. package/dist/lib/sales.js +155 -0
  68. package/dist/lib/sales.js.map +1 -0
  69. package/dist/lib/tasting.d.ts +76 -0
  70. package/dist/lib/tasting.d.ts.map +1 -0
  71. package/dist/lib/tasting.js +136 -0
  72. package/dist/lib/tasting.js.map +1 -0
  73. package/package.json +13 -2
@@ -0,0 +1,376 @@
1
+ /**
2
+ * Parser for Artisan .alog files which use Python literal syntax
3
+ * Converts Python literals to JSON format for processing
4
+ */
5
+ export function parseAlogFile(alogContent) {
6
+ // Convert Python literal syntax to JSON
7
+ let jsonContent = alogContent;
8
+ try {
9
+ // Replace Python boolean values with JSON equivalents (case-sensitive, whole words only)
10
+ jsonContent = jsonContent.replace(/\bTrue\b/g, 'true');
11
+ jsonContent = jsonContent.replace(/\bFalse\b/g, 'false');
12
+ jsonContent = jsonContent.replace(/\bNone\b/g, 'null');
13
+ // Handle Python-style comments (# comments) - remove them
14
+ // But be careful not to remove # characters inside strings (like hex colors)
15
+ jsonContent = removeCommentsCarefully(jsonContent);
16
+ // Convert single quotes to double quotes if present
17
+ if (jsonContent.includes("'")) {
18
+ jsonContent = convertSingleQuotesToDouble(jsonContent);
19
+ }
20
+ // Clean up control characters in strings
21
+ jsonContent = cleanControlCharacters(jsonContent);
22
+ // Fix common array/object formatting issues
23
+ jsonContent = fixFormattingIssues(jsonContent);
24
+ // Try to parse as JSON
25
+ const parsed = JSON.parse(jsonContent);
26
+ // Validate core temperature arrays
27
+ validateTemperatureArrays(parsed);
28
+ return parsed;
29
+ }
30
+ catch (error) {
31
+ // Enhanced error reporting with specific guidance
32
+ if (error instanceof Error) {
33
+ // If this is a validation error from our temperature array validation, re-throw as-is
34
+ if (error.message.includes('Missing required temperature array') ||
35
+ error.message.includes('Invalid temperature array') ||
36
+ error.message.includes('No profile data found')) {
37
+ throw error;
38
+ }
39
+ // For JSON parsing errors, provide better context
40
+ if (error instanceof SyntaxError && error.message.includes('position')) {
41
+ const match = error.message.match(/position (\d+)/);
42
+ if (match) {
43
+ const position = parseInt(match[1]);
44
+ const context = getErrorContext(jsonContent, position, 100);
45
+ throw new Error(`Failed to parse .alog file: ${error.message}\n\n` +
46
+ `This typically indicates:\n` +
47
+ `- Malformed Python literal syntax that couldn't be converted to JSON\n` +
48
+ `- Unescaped characters in string values\n` +
49
+ `- Incomplete or corrupted file data\n\n` +
50
+ `Error context: ...${context}...`);
51
+ }
52
+ }
53
+ }
54
+ throw new Error(`Invalid .alog file format: ${error instanceof Error ? error.message : 'Unknown error'}\n\n` +
55
+ `Please ensure the file is a valid Artisan .alog file with proper Python literal syntax.`);
56
+ }
57
+ }
58
+ function validateTemperatureArrays(parsed) {
59
+ const data = parsed;
60
+ const requiredArrays = ['timex', 'temp1', 'temp2'];
61
+ // Check that all required arrays exist
62
+ for (const arrayName of requiredArrays) {
63
+ if (!parsed[arrayName]) {
64
+ throw new Error(`Missing required temperature array: ${arrayName}`);
65
+ }
66
+ if (!Array.isArray(parsed[arrayName])) {
67
+ throw new Error(`Invalid temperature array: ${arrayName} must be an array`);
68
+ }
69
+ }
70
+ // Check that all arrays have the same length (as enforced by Artisan)
71
+ const timexLength = data.timex.length;
72
+ const temp1Length = data.temp1.length;
73
+ const temp2Length = data.temp2.length;
74
+ if (timexLength === 0) {
75
+ throw new Error('No profile data found: timex array is empty');
76
+ }
77
+ if (timexLength !== temp1Length || timexLength !== temp2Length) {
78
+ console.warn(`Temperature array length mismatch: timex=${timexLength}, temp1=${temp1Length}, temp2=${temp2Length}. ` +
79
+ 'Arrays will be truncated to minimum length as per Artisan behavior.');
80
+ // Truncate to minimum length (following Artisan's behavior)
81
+ const minLength = Math.min(timexLength, temp1Length, temp2Length);
82
+ parsed.timex = data.timex.slice(0, minLength);
83
+ parsed.temp1 = data.temp1.slice(0, minLength);
84
+ parsed.temp2 = data.temp2.slice(0, minLength);
85
+ }
86
+ // Validate that arrays contain valid numeric data
87
+ const validateNumericArray = (array, name) => {
88
+ for (let i = 0; i < array.length; i++) {
89
+ const val = array[i];
90
+ if (typeof val !== 'number' || isNaN(val)) {
91
+ throw new Error(`Invalid data in ${name} array at index ${i}: ${val}`);
92
+ }
93
+ }
94
+ };
95
+ validateNumericArray(data.timex, 'timex');
96
+ validateNumericArray(data.temp1, 'temp1');
97
+ validateNumericArray(data.temp2, 'temp2');
98
+ }
99
+ /**
100
+ * Remove Python-style comments while preserving # characters inside strings
101
+ */
102
+ function removeCommentsCarefully(content) {
103
+ let result = '';
104
+ let inString = false;
105
+ let escaped = false;
106
+ for (let i = 0; i < content.length; i++) {
107
+ const char = content[i];
108
+ if (escaped) {
109
+ result += char;
110
+ escaped = false;
111
+ continue;
112
+ }
113
+ if (char === '\\') {
114
+ escaped = true;
115
+ result += char;
116
+ continue;
117
+ }
118
+ if (char === '"') {
119
+ inString = !inString;
120
+ result += char;
121
+ continue;
122
+ }
123
+ // If we find a # outside of a string, it's a comment - remove everything until newline
124
+ if (char === '#' && !inString) {
125
+ // Skip everything until we find a newline
126
+ while (i < content.length && content[i] !== '\n' && content[i] !== '\r') {
127
+ i++;
128
+ }
129
+ // Don't increment i again in the for loop, let it handle the newline
130
+ i--;
131
+ continue;
132
+ }
133
+ result += char;
134
+ }
135
+ return result;
136
+ }
137
+ /**
138
+ * Clean up control characters in JSON strings
139
+ */
140
+ function cleanControlCharacters(content) {
141
+ let result = '';
142
+ let inString = false;
143
+ let escaped = false;
144
+ for (let i = 0; i < content.length; i++) {
145
+ const char = content[i];
146
+ if (escaped) {
147
+ result += char;
148
+ escaped = false;
149
+ continue;
150
+ }
151
+ if (char === '\\') {
152
+ escaped = true;
153
+ result += char;
154
+ continue;
155
+ }
156
+ if (char === '"') {
157
+ inString = !inString;
158
+ result += char;
159
+ continue;
160
+ }
161
+ // If we're inside a string, handle control characters
162
+ if (inString) {
163
+ const charCode = char.charCodeAt(0);
164
+ // Handle common control characters that need escaping in JSON
165
+ if (charCode < 32) {
166
+ switch (char) {
167
+ case '\n':
168
+ result += '\\n';
169
+ break;
170
+ case '\r':
171
+ result += '\\r';
172
+ break;
173
+ case '\t':
174
+ result += '\\t';
175
+ break;
176
+ case '\b':
177
+ result += '\\b';
178
+ break;
179
+ case '\f':
180
+ result += '\\f';
181
+ break;
182
+ default:
183
+ // For other control characters, use unicode escape
184
+ result += '\\u' + charCode.toString(16).padStart(4, '0');
185
+ break;
186
+ }
187
+ }
188
+ else {
189
+ result += char;
190
+ }
191
+ }
192
+ else {
193
+ result += char;
194
+ }
195
+ }
196
+ return result;
197
+ }
198
+ /**
199
+ * Convert Python-style single quotes to double quotes while preserving string content
200
+ */
201
+ function convertSingleQuotesToDouble(content) {
202
+ let result = '';
203
+ let inDoubleQuotes = false;
204
+ let inSingleQuotes = false;
205
+ let escaped = false;
206
+ for (let i = 0; i < content.length; i++) {
207
+ const char = content[i];
208
+ if (escaped) {
209
+ result += char;
210
+ escaped = false;
211
+ continue;
212
+ }
213
+ if (char === '\\') {
214
+ escaped = true;
215
+ result += char;
216
+ continue;
217
+ }
218
+ if (char === '"' && !inSingleQuotes) {
219
+ inDoubleQuotes = !inDoubleQuotes;
220
+ result += char;
221
+ }
222
+ else if (char === "'" && !inDoubleQuotes) {
223
+ // Check if this is likely a property name or string value
224
+ // Skip apostrophes that are likely part of contractions
225
+ const nextChar = i + 1 < content.length ? content[i + 1] : '';
226
+ const prevChar = i > 0 ? content[i - 1] : '';
227
+ // Skip apostrophes in contractions like "don't", "can't", etc.
228
+ if (prevChar.match(/[a-zA-Z]/) && nextChar.match(/[a-zA-Z]/)) {
229
+ result += char;
230
+ continue;
231
+ }
232
+ if (inSingleQuotes) {
233
+ // End of single-quoted string - convert to double quote
234
+ result += '"';
235
+ inSingleQuotes = false;
236
+ }
237
+ else {
238
+ // Start of single-quoted string - convert to double quote
239
+ result += '"';
240
+ inSingleQuotes = true;
241
+ }
242
+ }
243
+ else {
244
+ result += char;
245
+ }
246
+ }
247
+ // Safety check: if we ended in single quotes, close the string
248
+ if (inSingleQuotes) {
249
+ console.warn('Warning: Unterminated single quote detected, adding closing quote');
250
+ result += '"';
251
+ }
252
+ return result;
253
+ }
254
+ /**
255
+ * Validate that a file is likely an Artisan .alog file
256
+ */
257
+ export function isValidAlogFile(content) {
258
+ const trimmed = content.trim();
259
+ // Must be a JSON-like object structure
260
+ if (!trimmed.startsWith('{') || !trimmed.endsWith('}')) {
261
+ return false;
262
+ }
263
+ // Must contain core temperature data arrays (the essential markers)
264
+ const hasTemperatureArrays = (content.includes('"timex"') || content.includes("'timex'")) &&
265
+ (content.includes('"temp1"') || content.includes("'temp1'")) &&
266
+ (content.includes('"temp2"') || content.includes("'temp2'"));
267
+ if (!hasTemperatureArrays) {
268
+ return false;
269
+ }
270
+ // Should have typical Artisan profile markers
271
+ const hasArtisanMarkers = content.includes('"version"') ||
272
+ content.includes("'version'") ||
273
+ content.includes('"roastdate"') ||
274
+ content.includes("'roastdate'") ||
275
+ content.includes('"beans"') ||
276
+ content.includes("'beans'");
277
+ // Should have Python literal syntax if it's an .alog file
278
+ const hasPythonSyntax = content.includes('True') || content.includes('False') || content.includes('None');
279
+ return hasTemperatureArrays && (hasArtisanMarkers || hasPythonSyntax);
280
+ }
281
+ /**
282
+ * Clean up common .alog file formatting issues
283
+ */
284
+ export function preprocessAlogContent(content) {
285
+ // Remove any BOM (Byte Order Mark)
286
+ content = content.replace(/^\uFEFF/, '');
287
+ // Normalize line endings
288
+ content = content.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
289
+ // Remove any trailing whitespace/newlines
290
+ content = content.trim();
291
+ return content;
292
+ }
293
+ /**
294
+ * Fix common formatting issues that can cause JSON parsing errors
295
+ */
296
+ function fixFormattingIssues(content) {
297
+ // Remove trailing commas in arrays and objects
298
+ content = content.replace(/,(\s*[}\]])/g, '$1');
299
+ // Fix double commas
300
+ content = content.replace(/,,+/g, ',');
301
+ // Fix empty elements in arrays (like [,] or [1,,2])
302
+ content = content.replace(/\[\s*,/g, '[');
303
+ content = content.replace(/,\s*,/g, ',');
304
+ content = content.replace(/,\s*\]/g, ']');
305
+ // Handle malformed arrays systematically
306
+ content = fixMalformedArrays(content);
307
+ return content;
308
+ }
309
+ /**
310
+ * Systematically fix malformed array patterns found in .alog files
311
+ */
312
+ function fixMalformedArrays(content) {
313
+ // Robust array cleanup using systematic validation and reconstruction
314
+ // Strategy: Nuclear option - identify and safely convert problematic arrays to empty arrays
315
+ // Step 1: Handle arrays with unmatched quotes (major parsing killer)
316
+ content = content.replace(/:\s*\[[^\]]*"[^"\]]*$/gm, (match) => {
317
+ const propertyMatch = match.match(/^([^:]*:)/);
318
+ return propertyMatch ? propertyMatch[1] + ' []' : ': []';
319
+ });
320
+ // Step 2: Handle arrays with incomplete elements at end of lines
321
+ content = content.replace(/:\s*\[[^\]]*,[^,\]"]*$/gm, (match) => {
322
+ const propertyMatch = match.match(/^([^:]*:)/);
323
+ return propertyMatch ? propertyMatch[1] + ' []' : ': []';
324
+ });
325
+ // Step 3: Fix arrays that contain only empty strings or whitespace
326
+ content = content.replace(/:\s*\[\s*""\s*\]/g, ': []');
327
+ content = content.replace(/:\s*\[\s*\]/g, ': []');
328
+ // Step 4: Nuclear option for color arrays (consistently problematic)
329
+ content = content.replace(/"[^"]*color[^"]*":\s*\[[^\]]*\]/gi, (match) => {
330
+ const propertyMatch = match.match(/"([^"]*)"/);
331
+ const propertyName = propertyMatch ? propertyMatch[1] : 'color_property';
332
+ return `"${propertyName}": []`;
333
+ });
334
+ // Step 5: Fix trailing comma issues in arrays
335
+ content = content.replace(/,(\s*\])/g, '$1');
336
+ // Step 6: Final safety net - any array that doesn't have proper structure gets emptied
337
+ // Look for arrays that start but don't properly close before next property or end
338
+ content = content.replace(/:\s*\[(?![^\]]*\](?:\s*,|\s*}))[^\]]*(?=\s*"[^"]*"\s*:|$)/gm, ': []');
339
+ return content;
340
+ }
341
+ /**
342
+ * Get context around an error position for better debugging
343
+ */
344
+ function getErrorContext(content, position, contextLength = 50) {
345
+ const start = Math.max(0, position - contextLength);
346
+ const end = Math.min(content.length, position + contextLength);
347
+ return content.substring(start, end);
348
+ }
349
+ /**
350
+ * Main entry point for .alog file processing (formerly processAlogFile).
351
+ * Preprocesses, validates, and parses Artisan .alog files.
352
+ */
353
+ export function processAlogFile(fileContent) {
354
+ try {
355
+ // Preprocess the content to normalize format
356
+ const cleanContent = preprocessAlogContent(fileContent);
357
+ // Validate it looks like an .alog file before attempting to parse
358
+ if (!isValidAlogFile(cleanContent)) {
359
+ throw new Error('File does not appear to be a valid Artisan .alog file.\n\n' +
360
+ 'Expected: JSON-like object with timex, temp1, and temp2 temperature arrays.\n' +
361
+ 'Please ensure this is an Artisan roast profile file (.alog format).');
362
+ }
363
+ // Parse the Python literal syntax to JSON and validate
364
+ return parseAlogFile(cleanContent);
365
+ }
366
+ catch (error) {
367
+ // Re-throw with context if it's already our enhanced error
368
+ if (error instanceof Error && error.message.includes('This typically indicates')) {
369
+ throw error;
370
+ }
371
+ // Otherwise wrap with general guidance
372
+ throw new Error(`Failed to process .alog file: ${error instanceof Error ? error.message : 'Unknown error'}\n\n` +
373
+ 'Please ensure the file is a valid, complete Artisan roast profile (.alog) file.');
374
+ }
375
+ }
376
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.js","sourceRoot":"","sources":["../../../src/lib/artisan/parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Temperature conversion utilities for Artisan roast data
3
+ */
4
+ export type TemperatureUnit = 'F' | 'C';
5
+ /**
6
+ * Convert temperature between Fahrenheit and Celsius
7
+ */
8
+ export declare function convertTemperature(value: number, from: TemperatureUnit, to: TemperatureUnit): number;
9
+ /**
10
+ * Convert temperature array with safe null handling
11
+ */
12
+ export declare function convertTemperatureArray(values: (number | null)[], from: TemperatureUnit, to: TemperatureUnit): (number | null)[];
13
+ /**
14
+ * Format temperature value with unit for display
15
+ */
16
+ export declare function formatTemperature(value: number | null, unit: TemperatureUnit, displayUnit?: TemperatureUnit, precision?: number): string;
17
+ /**
18
+ * Get temperature range for scale calculation
19
+ */
20
+ export declare function getTemperatureRange(beanTemps: (number | null)[], envTemps: (number | null)[], padding?: number): [number, number];
21
+ /**
22
+ * Normalize temperature data to a target unit
23
+ * This is the main function for processing Artisan data
24
+ *
25
+ * IMPORTANT: In Artisan .alog files:
26
+ * - temp1 = Environmental Temperature (ET)
27
+ * - temp2 = Bean Temperature (BT)
28
+ */
29
+ export declare function normalizeArtisanTemperatures(temp1: number[], // Environmental Temperature (ET) - from Artisan temp1 array
30
+ temp2: number[], // Bean Temperature (BT) - from Artisan temp2 array
31
+ sourceUnit: TemperatureUnit, targetUnit?: TemperatureUnit): {
32
+ beanTemps: number[];
33
+ envTemps: number[];
34
+ unit: TemperatureUnit;
35
+ };
36
+ /**
37
+ * Safe temperature parsing with validation
38
+ */
39
+ export declare function parseTemperature(value: unknown): number | null;
40
+ /**
41
+ * Validate temperature unit
42
+ */
43
+ export declare function isValidTemperatureUnit(unit: unknown): unit is TemperatureUnit;
44
+ /**
45
+ * Get default temperature unit based on locale/region
46
+ */
47
+ export declare function getDefaultTemperatureUnit(): TemperatureUnit;
48
+ /**
49
+ * Convert Artisan mode field to temperature unit
50
+ */
51
+ export declare function artisanModeToUnit(mode: string): TemperatureUnit;
52
+ //# sourceMappingURL=temperature.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"temperature.d.ts","sourceRoot":"","sources":["../../../src/lib/artisan/temperature.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,eAAe,GAAG,GAAG,GAAG,GAAG,CAAC;AAExC;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,eAAe,EACrB,EAAE,EAAE,eAAe,GAClB,MAAM,CAQR;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,EACzB,IAAI,EAAE,eAAe,EACrB,EAAE,EAAE,eAAe,GAClB,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAOnB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,GAAG,IAAI,EACpB,IAAI,EAAE,eAAe,EACrB,WAAW,CAAC,EAAE,eAAe,EAC7B,SAAS,GAAE,MAAU,GACpB,MAAM,CAOR;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,EAC5B,QAAQ,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,EAC3B,OAAO,GAAE,MAAW,GACnB,CAAC,MAAM,EAAE,MAAM,CAAC,CAWlB;AAED;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAC1C,KAAK,EAAE,MAAM,EAAE,EAAE,4DAA4D;AAC7E,KAAK,EAAE,MAAM,EAAE,EAAE,mDAAmD;AACpE,UAAU,EAAE,eAAe,EAC3B,UAAU,GAAE,eAAqB,GAChC;IACD,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,IAAI,EAAE,eAAe,CAAC;CACvB,CAMA;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAW9D;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,eAAe,CAE7E;AAED;;GAEG;AACH,wBAAgB,yBAAyB,IAAI,eAAe,CAG3D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,CAG/D"}
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Temperature conversion utilities for Artisan roast data
3
+ */
4
+ /**
5
+ * Convert temperature between Fahrenheit and Celsius
6
+ */
7
+ export function convertTemperature(value, from, to) {
8
+ if (from === to)
9
+ return value;
10
+ if (from === 'F' && to === 'C') {
11
+ return ((value - 32) * 5) / 9;
12
+ }
13
+ else {
14
+ return (value * 9) / 5 + 32;
15
+ }
16
+ }
17
+ /**
18
+ * Convert temperature array with safe null handling
19
+ */
20
+ export function convertTemperatureArray(values, from, to) {
21
+ if (from === to)
22
+ return values;
23
+ return values.map((value) => {
24
+ if (value === null || value === undefined)
25
+ return null;
26
+ return convertTemperature(value, from, to);
27
+ });
28
+ }
29
+ /**
30
+ * Format temperature value with unit for display
31
+ */
32
+ export function formatTemperature(value, unit, displayUnit, precision = 1) {
33
+ if (value === null || value === undefined)
34
+ return '--';
35
+ const displayValue = displayUnit && displayUnit !== unit ? convertTemperature(value, unit, displayUnit) : value;
36
+ return `${displayValue.toFixed(precision)}°${displayUnit || unit}`;
37
+ }
38
+ /**
39
+ * Get temperature range for scale calculation
40
+ */
41
+ export function getTemperatureRange(beanTemps, envTemps, padding = 50) {
42
+ const allTemps = [...beanTemps, ...envTemps].filter((t) => t !== null);
43
+ if (allTemps.length === 0) {
44
+ return [0, 500]; // Default range
45
+ }
46
+ const min = Math.min(...allTemps);
47
+ const max = Math.max(...allTemps);
48
+ return [min - padding, max + padding];
49
+ }
50
+ /**
51
+ * Normalize temperature data to a target unit
52
+ * This is the main function for processing Artisan data
53
+ *
54
+ * IMPORTANT: In Artisan .alog files:
55
+ * - temp1 = Environmental Temperature (ET)
56
+ * - temp2 = Bean Temperature (BT)
57
+ */
58
+ export function normalizeArtisanTemperatures(temp1, // Environmental Temperature (ET) - from Artisan temp1 array
59
+ temp2, // Bean Temperature (BT) - from Artisan temp2 array
60
+ sourceUnit, targetUnit = 'F') {
61
+ return {
62
+ beanTemps: temp2.map((t) => convertTemperature(t, sourceUnit, targetUnit)), // temp2 = BT
63
+ envTemps: temp1.map((t) => convertTemperature(t, sourceUnit, targetUnit)), // temp1 = ET
64
+ unit: targetUnit,
65
+ };
66
+ }
67
+ /**
68
+ * Safe temperature parsing with validation
69
+ */
70
+ export function parseTemperature(value) {
71
+ if (value === null || value === undefined || value === '')
72
+ return null;
73
+ const parsed = typeof value === 'number' ? value : parseFloat(String(value));
74
+ // Check for invalid values that Artisan might export
75
+ if (isNaN(parsed) || parsed === -1.0 || parsed < -273.15 || parsed > 1000) {
76
+ return null;
77
+ }
78
+ return parsed;
79
+ }
80
+ /**
81
+ * Validate temperature unit
82
+ */
83
+ export function isValidTemperatureUnit(unit) {
84
+ return unit === 'F' || unit === 'C';
85
+ }
86
+ /**
87
+ * Get default temperature unit based on locale/region
88
+ */
89
+ export function getDefaultTemperatureUnit() {
90
+ // Default to Fahrenheit for coffee roasting (most common)
91
+ return 'F';
92
+ }
93
+ /**
94
+ * Convert Artisan mode field to temperature unit
95
+ */
96
+ export function artisanModeToUnit(mode) {
97
+ if (mode === 'C')
98
+ return 'C';
99
+ return 'F'; // Default to Fahrenheit if not explicitly Celsius
100
+ }
101
+ //# sourceMappingURL=temperature.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"temperature.js","sourceRoot":"","sources":["../../../src/lib/artisan/temperature.ts"],"names":[],"mappings":"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"}