Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | 57x 57x 5037x 5003x 57x 26x 22x 7x 7x 7x 57x 57x 57x 57x 4969x 4969x 4969x 4969x 4969x 4969x 4951x 4969x 57x 5060x 2x 5037x 57x 5001x 57x 1x 2x 1x 4x 1x 5010x 5009x 1x 22x | /**
* Compiler Output Parser
*
* Centralizes Arduino CLI output parsing logic including:
* - Error/warning extraction from gcc-style error messages
* - Deduplication of error entries
* - Fallback generic error parsing when regex doesn't match
*/
import { basename } from "node:path";
export interface CompilationError {
file: string;
line: number;
column: number;
type: 'error' | 'warning';
message: string;
}
export class CompilerOutputParser {
/**
* Parse compiler stderr output into structured error list.
*
* Handles patterns like:
* - 'file:line:column: error: message'
* - 'file:line: error: message' (column optional)
* - Falls back to per-line generic errors if regex doesn't match
*
* @param stderr Raw stderr output from arduino-cli
* @param lineOffset Optional offset to adjust line numbers (e.g., header injection)
* @returns Array of structured compilation errors/warnings
*/
static parseErrors(stderr: string, lineOffset: number = 0): CompilationError[] {
const results = parseStructuredErrors(stderr, lineOffset);
appendUnique(results, parseMemoryOverflow(stderr));
for (const line of stderr.split(/\r?\n/).filter((l) => l.trim())) {
appendUnique(results, parseLibraryScanWarning(line));
}
// if nothing parsed but stderr is present, create generic entries per line
if (results.length === 0 && stderr.trim()) {
for (const line of stderr.split(/\r?\n/).filter((l) => l.trim())) {
if (isInformationalCompilerLine(line)) continue;
const libraryWarning = parseLibraryScanWarning(line);
Iif (libraryWarning) {
results.push(libraryWarning);
continue;
}
results.push({
file: "",
line: 0,
column: 0,
type: "error",
message: line.trim(),
});
}
}
return results;
}
}
function parseStructuredErrors(stderr: string, lineOffset: number): CompilationError[] {
const regex = /^([^:\n]+):(\d+)(?::(\d+))?: +(warning|error): +([^\n]*)$/gm; // NOSONAR S5843
const results: CompilationError[] = [];
let match: RegExpExecArray | null;
while ((match = regex.exec(stderr))) {
const [, rawFile, lineStr, colStr, type, message] = match;
const file = basename(rawFile);
const line = lineOffset > 0
? Math.max(1, Number.parseInt(lineStr, 10) - lineOffset)
: Number.parseInt(lineStr, 10);
const column = colStr ? Number.parseInt(colStr, 10) : 0;
const item: CompilationError = {
file,
line,
column,
type: type as 'error' | 'warning',
message,
};
const duplicate = results.some((result) =>
result.file === item.file &&
result.line === item.line &&
result.column === item.column &&
result.type === item.type &&
result.message === item.message,
);
if (!duplicate) results.push(item);
}
return results;
}
function appendUnique(results: CompilationError[], item: CompilationError | undefined): void {
if (!item || results.some((result) => result.message === item.message)) return;
results.push(item);
}
function parseMemoryOverflow(output: string): CompilationError | undefined {
const lines = output.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
const hasMemoryOverflow = lines.some((line) =>
/not enough memory|data section exceeds available space(?: in| on) board/i.test(line),
);
if (!hasMemoryOverflow) return undefined;
const flashUsage = lines.find((line) => /^sketch uses\b|^der sketch verwendet\b/i.test(line));
const sramUsage = lines.find((line) => /^global variables use\b|^globale variablen verwenden\b/i.test(line));
const details = [flashUsage, sramUsage].filter(Boolean).join(" ");
const reason = lines.find((line) => /data section exceeds available space/i.test(line));
return {
file: "",
line: 0,
column: 0,
type: "error",
message: [
"Not enough memory",
reason ? `${reason}.` : "Memory usage exceeds the board limit.",
details,
].filter(Boolean).join(" "),
};
}
function parseLibraryScanWarning(line: string): CompilationError | undefined {
if (!/(?:warning\s*:\s*library\b|multiple libraries were found|library .*\b(?:not found|incompatible|failed)\b)/i.test(line)) {
return undefined;
}
return {
file: "",
line: 0,
column: 0,
type: "warning",
message: line.trim().replace(/^warning\s*:\s*/i, ""),
};
}
function isInformationalCompilerLine(line: string): boolean {
return /^(?:sketch uses|global variables use|der sketch verwendet|globale variablen verwenden)\b/i.test(line.trim());
}
|