2026-03-06 07:07:03 +07:00
|
|
|
/**
|
|
|
|
|
* Parse a CompileResult into CompilationLog entries for display in the console.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
import type { CompileResult } from '../services/compilation';
|
|
|
|
|
|
|
|
|
|
export interface CompilationLog {
|
|
|
|
|
timestamp: Date;
|
|
|
|
|
type: 'info' | 'success' | 'error' | 'warning' | 'core-install';
|
|
|
|
|
message: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function parseCompileResult(result: CompileResult, board: string): CompilationLog[] {
|
|
|
|
|
const logs: CompilationLog[] = [];
|
|
|
|
|
const now = new Date();
|
|
|
|
|
|
|
|
|
|
logs.push({ timestamp: now, type: 'info', message: `Compiling for ${board}...` });
|
|
|
|
|
|
|
|
|
|
// Core install log
|
|
|
|
|
if (result.core_install_log) {
|
|
|
|
|
for (const line of result.core_install_log.split('\n')) {
|
|
|
|
|
if (line.trim()) {
|
|
|
|
|
logs.push({ timestamp: now, type: 'core-install', message: line });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-08 00:59:51 +07:00
|
|
|
// stdout — for ESP-IDF/ninja builds, compiler errors appear here
|
2026-03-06 07:07:03 +07:00
|
|
|
if (result.stdout) {
|
2026-04-08 00:59:51 +07:00
|
|
|
let inFailedBlock = false;
|
2026-03-06 07:07:03 +07:00
|
|
|
for (const line of result.stdout.split('\n')) {
|
2026-04-08 00:59:51 +07:00
|
|
|
if (!line.trim()) continue;
|
|
|
|
|
const stripped = line.trim();
|
|
|
|
|
// Ninja FAILED block start
|
|
|
|
|
if (stripped.startsWith('FAILED:') || stripped === 'ninja: build stopped: subcommand failed.') {
|
|
|
|
|
inFailedBlock = true;
|
|
|
|
|
logs.push({ timestamp: now, type: 'error', message: line });
|
|
|
|
|
continue;
|
2026-03-06 07:07:03 +07:00
|
|
|
}
|
2026-04-08 00:59:51 +07:00
|
|
|
// Progress line [N/M] ends a FAILED block
|
|
|
|
|
if (inFailedBlock && /^\[\d+\/\d+\]/.test(stripped)) {
|
|
|
|
|
inFailedBlock = false;
|
|
|
|
|
}
|
|
|
|
|
// Classify the line
|
|
|
|
|
let type: CompilationLog['type'];
|
|
|
|
|
if (inFailedBlock) {
|
|
|
|
|
// Lines inside a FAILED block: compiler output — detect subcategory
|
|
|
|
|
type = /:\s*(fatal )?error:/i.test(line) ? 'error' : 'warning';
|
|
|
|
|
} else if (/:\s*(fatal )?error:/i.test(line) && !/^\[/.test(stripped)) {
|
|
|
|
|
type = 'error';
|
|
|
|
|
} else if (/:\s*warning:/i.test(line) || line.toLowerCase().includes('warning')) {
|
|
|
|
|
type = 'warning';
|
|
|
|
|
} else {
|
|
|
|
|
type = 'info';
|
|
|
|
|
}
|
|
|
|
|
logs.push({ timestamp: now, type, message: line });
|
2026-03-06 07:07:03 +07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// stderr — classify lines as warnings or errors
|
|
|
|
|
if (result.stderr) {
|
|
|
|
|
for (const line of result.stderr.split('\n')) {
|
|
|
|
|
if (!line.trim()) continue;
|
|
|
|
|
let type: CompilationLog['type'] = 'error';
|
|
|
|
|
const lower = line.toLowerCase();
|
|
|
|
|
if (lower.includes('warning:') || lower.includes('warn ')) {
|
|
|
|
|
type = 'warning';
|
|
|
|
|
} else if (lower.includes('note:') || lower.includes('in file included') || lower.startsWith('using ') || lower.startsWith('libraries ')) {
|
|
|
|
|
type = 'info';
|
|
|
|
|
}
|
|
|
|
|
logs.push({ timestamp: now, type, message: line });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Final status
|
|
|
|
|
if (result.success) {
|
|
|
|
|
logs.push({ timestamp: now, type: 'success', message: '✓ Compilation successful' });
|
|
|
|
|
} else {
|
|
|
|
|
const errorMsg = result.error || 'Compilation failed';
|
|
|
|
|
logs.push({ timestamp: now, type: 'error', message: `✕ ${errorMsg}` });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return logs;
|
|
|
|
|
}
|