@purveyors/cli 0.2.1 → 0.4.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.
- package/dist/commands/catalog.d.ts +4 -56
- package/dist/commands/catalog.d.ts.map +1 -1
- package/dist/commands/catalog.js +14 -81
- package/dist/commands/catalog.js.map +1 -1
- package/dist/commands/config.d.ts +7 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +82 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/inventory.d.ts +2 -25
- package/dist/commands/inventory.d.ts.map +1 -1
- package/dist/commands/inventory.js +109 -149
- package/dist/commands/inventory.js.map +1 -1
- package/dist/commands/roast.d.ts +2 -41
- package/dist/commands/roast.d.ts.map +1 -1
- package/dist/commands/roast.js +445 -126
- package/dist/commands/roast.js.map +1 -1
- package/dist/commands/sales.d.ts +2 -10
- package/dist/commands/sales.d.ts.map +1 -1
- package/dist/commands/sales.js +100 -112
- package/dist/commands/sales.js.map +1 -1
- package/dist/commands/tasting.d.ts +4 -38
- package/dist/commands/tasting.d.ts.map +1 -1
- package/dist/commands/tasting.js +93 -116
- package/dist/commands/tasting.js.map +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/ai.d.ts +36 -0
- package/dist/lib/ai.d.ts.map +1 -0
- package/dist/lib/ai.js +38 -0
- package/dist/lib/ai.js.map +1 -0
- package/dist/lib/artisan/db.d.ts +37 -0
- package/dist/lib/artisan/db.d.ts.map +1 -0
- package/dist/lib/artisan/db.js +51 -0
- package/dist/lib/artisan/db.js.map +1 -0
- package/dist/lib/artisan/import.d.ts +16 -0
- package/dist/lib/artisan/import.d.ts.map +1 -0
- package/dist/lib/artisan/import.js +447 -0
- package/dist/lib/artisan/import.js.map +1 -0
- package/dist/lib/artisan/index.d.ts +9 -0
- package/dist/lib/artisan/index.d.ts.map +1 -0
- package/dist/lib/artisan/index.js +7 -0
- package/dist/lib/artisan/index.js.map +1 -0
- package/dist/lib/artisan/parser.d.ts +19 -0
- package/dist/lib/artisan/parser.d.ts.map +1 -0
- package/dist/lib/artisan/parser.js +376 -0
- package/dist/lib/artisan/parser.js.map +1 -0
- package/dist/lib/artisan/temperature.d.ts +52 -0
- package/dist/lib/artisan/temperature.d.ts.map +1 -0
- package/dist/lib/artisan/temperature.js +101 -0
- package/dist/lib/artisan/temperature.js.map +1 -0
- package/dist/lib/artisan/types.d.ts +195 -0
- package/dist/lib/artisan/types.d.ts.map +1 -0
- package/dist/lib/artisan/types.js +35 -0
- package/dist/lib/artisan/types.js.map +1 -0
- package/dist/lib/artisan/validator.d.ts +14 -0
- package/dist/lib/artisan/validator.d.ts.map +1 -0
- package/dist/lib/artisan/validator.js +228 -0
- package/dist/lib/artisan/validator.js.map +1 -0
- package/dist/lib/catalog.d.ts +87 -0
- package/dist/lib/catalog.d.ts.map +1 -0
- package/dist/lib/catalog.js +111 -0
- package/dist/lib/catalog.js.map +1 -0
- package/dist/lib/config.d.ts +26 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +59 -0
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/index.d.ts +6 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/index.js +11 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/interactive/forms.d.ts +33 -0
- package/dist/lib/interactive/forms.d.ts.map +1 -0
- package/dist/lib/interactive/forms.js +139 -0
- package/dist/lib/interactive/forms.js.map +1 -0
- package/dist/lib/interactive/watch.d.ts +66 -0
- package/dist/lib/interactive/watch.d.ts.map +1 -0
- package/dist/lib/interactive/watch.js +494 -0
- package/dist/lib/interactive/watch.js.map +1 -0
- package/dist/lib/inventory.d.ts +80 -0
- package/dist/lib/inventory.d.ts.map +1 -0
- package/dist/lib/inventory.js +205 -0
- package/dist/lib/inventory.js.map +1 -0
- package/dist/lib/roast.d.ts +127 -0
- package/dist/lib/roast.d.ts.map +1 -0
- package/dist/lib/roast.js +284 -0
- package/dist/lib/roast.js.map +1 -0
- package/dist/lib/sales.d.ts +53 -0
- package/dist/lib/sales.d.ts.map +1 -0
- package/dist/lib/sales.js +155 -0
- package/dist/lib/sales.js.map +1 -0
- package/dist/lib/tasting.d.ts +76 -0
- package/dist/lib/tasting.d.ts.map +1 -0
- package/dist/lib/tasting.js +136 -0
- package/dist/lib/tasting.js.map +1 -0
- package/package.json +15 -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":"AAAA;;GAEG;AAIH;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAChC,KAAa,EACb,IAAqB,EACrB,EAAmB;IAEnB,IAAI,IAAI,KAAK,EAAE;QAAE,OAAO,KAAK,CAAC;IAE9B,IAAI,IAAI,KAAK,GAAG,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;QAC/B,OAAO,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;IAChC,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;IAC9B,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,uBAAuB,CACrC,MAAyB,EACzB,IAAqB,EACrB,EAAmB;IAEnB,IAAI,IAAI,KAAK,EAAE;QAAE,OAAO,MAAM,CAAC;IAE/B,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QAC1B,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,IAAI,CAAC;QACvD,OAAO,kBAAkB,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAC/B,KAAoB,EACpB,IAAqB,EACrB,WAA6B,EAC7B,YAAoB,CAAC;IAErB,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IAEvD,MAAM,YAAY,GAChB,WAAW,IAAI,WAAW,KAAK,IAAI,CAAC,CAAC,CAAC,kBAAkB,CAAC,KAAK,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IAE7F,OAAO,GAAG,YAAY,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,WAAW,IAAI,IAAI,EAAE,CAAC;AACrE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CACjC,SAA4B,EAC5B,QAA2B,EAC3B,UAAkB,EAAE;IAEpB,MAAM,QAAQ,GAAG,CAAC,GAAG,SAAS,EAAE,GAAG,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI,CAAa,CAAC;IAEnF,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,gBAAgB;IACnC,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC;IAClC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC;IAElC,OAAO,CAAC,GAAG,GAAG,OAAO,EAAE,GAAG,GAAG,OAAO,CAAC,CAAC;AACxC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,4BAA4B,CAC1C,KAAe,EAAE,4DAA4D;AAC7E,KAAe,EAAE,mDAAmD;AACpE,UAA2B,EAC3B,aAA8B,GAAG;IAMjC,OAAO;QACL,SAAS,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC,EAAE,aAAa;QACzF,QAAQ,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC,EAAE,aAAa;QACxF,IAAI,EAAE,UAAU;KACjB,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC;IAEvE,MAAM,MAAM,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAE7E,qDAAqD;IACrD,IAAI,KAAK,CAAC,MAAM,CAAC,IAAI,MAAM,KAAK,CAAC,GAAG,IAAI,MAAM,GAAG,CAAC,MAAM,IAAI,MAAM,GAAG,IAAI,EAAE,CAAC;QAC1E,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,sBAAsB,CAAC,IAAa;IAClD,OAAO,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,CAAC;AACtC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,yBAAyB;IACvC,0DAA0D;IAC1D,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,IAAI,IAAI,KAAK,GAAG;QAAE,OAAO,GAAG,CAAC;IAC7B,OAAO,GAAG,CAAC,CAAC,kDAAkD;AAChE,CAAC"}
|