feat(editor): per-target compilation console — a section per board/chip
Phase 4 of the run-system work. The compile console now groups output into a
section per run target (board or chip) with a status glyph and label, the way
multiple Arduinos already stream — instead of one flat list.
- CompilationLog gains an optional target { id, label, kind: 'board'|'chip' }.
message/type are unchanged so the pro overlay (diagnose-with-AI prompt +
errorCount slot) and the console's length-based clear/auto-error heuristics
are untouched. parseCompileResult stamps the target on every produced line.
- Producers stamp their lines: compileAllBoards (per-board, dropping the old
'<label>: ' string prefix the header now carries), prepareCustomChips
(per-chip, WASM + ROM), handleCompile + handleRun MicroPython (single board) —
including the Pi / MicroPython / FQBN / error paths so a target's lines never
fragment across sections.
- CompilationConsole groups filteredLogs into consecutive-run sections at RENDER
time only (the flat array is unchanged); each target section shows ✓/✕/▸ +
name + kind tag, with no-target lines ('Compiling all targets', 'Done') as
plain narration around them.
Reviewed by an adversarial pass; the flagged un-stamped edge paths (Pi /
MicroPython / single-board errors) are now stamped.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
6ae1ed560d
commit
dd322b27e3
|
|
@ -5,7 +5,37 @@
|
|||
|
||||
import React, { useRef, useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import type { CompilationLog } from '../../utils/compilationLogger';
|
||||
import type { CompilationLog, CompileTarget } from '../../utils/compilationLogger';
|
||||
|
||||
/** One contiguous run of log lines for the same target (or none). */
|
||||
interface LogGroup {
|
||||
target?: CompileTarget;
|
||||
entries: { log: CompilationLog; index: number }[];
|
||||
}
|
||||
|
||||
/** Group consecutive log lines by target so the console renders a section per
|
||||
* board/chip. Consecutive-run (not collapse-all) preserves chronological order
|
||||
* — a leading "Compiling all targets" and a trailing "Done" stay where they
|
||||
* are, around the per-target sections. */
|
||||
function groupLogs(logs: CompilationLog[]): LogGroup[] {
|
||||
const groups: LogGroup[] = [];
|
||||
logs.forEach((log, index) => {
|
||||
const last = groups[groups.length - 1];
|
||||
if (last && (last.target?.id ?? null) === (log.target?.id ?? null)) {
|
||||
last.entries.push({ log, index });
|
||||
} else {
|
||||
groups.push({ target: log.target, entries: [{ log, index }] });
|
||||
}
|
||||
});
|
||||
return groups;
|
||||
}
|
||||
|
||||
/** A target section's overall outcome, derived from its lines. */
|
||||
function groupStatus(entries: LogGroup['entries']): 'error' | 'success' | 'running' {
|
||||
if (entries.some((e) => e.log.type === 'error')) return 'error';
|
||||
if (entries.some((e) => e.log.type === 'success')) return 'success';
|
||||
return 'running';
|
||||
}
|
||||
|
||||
interface CompilationConsoleProps {
|
||||
isOpen: boolean;
|
||||
|
|
@ -154,33 +184,65 @@ export const CompilationConsole: React.FC<CompilationConsoleProps> = ({
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{/* Output content */}
|
||||
{/* Output content — grouped into a section per board/chip target. */}
|
||||
<div ref={outputRef} style={styles.output}>
|
||||
{filteredLogs.length === 0 ? (
|
||||
<div style={styles.emptyState}>{t('editor.console.empty')}</div>
|
||||
) : (
|
||||
filteredLogs.map((log, i) => (
|
||||
<div key={i} style={styles.logLine}>
|
||||
<span style={styles.timestamp}>
|
||||
{log.timestamp.toLocaleTimeString('en-US', {
|
||||
hour12: false,
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit',
|
||||
})}
|
||||
</span>
|
||||
<span style={{ ...styles.logMessage, color: logColor(log.type) }}>
|
||||
{log.type === 'core-install' && <span style={styles.coreTag}>CORE </span>}
|
||||
{log.message}
|
||||
</span>
|
||||
</div>
|
||||
))
|
||||
groupLogs(filteredLogs).map((group, gi) =>
|
||||
group.target ? (
|
||||
<div key={`g-${gi}`} style={styles.targetGroup}>
|
||||
<div style={styles.targetHeader}>
|
||||
<span
|
||||
style={{ ...styles.targetStatus, color: statusColor(groupStatus(group.entries)) }}
|
||||
>
|
||||
{statusGlyph(groupStatus(group.entries))}
|
||||
</span>
|
||||
<span style={styles.targetLabel}>{group.target.label}</span>
|
||||
<span style={styles.targetKind}>{group.target.kind}</span>
|
||||
</div>
|
||||
<div style={styles.targetBody}>
|
||||
{group.entries.map(({ log, index }) => (
|
||||
<LogLine key={index} log={log} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
// No target — plain narration ("Compiling all targets...", "Done").
|
||||
group.entries.map(({ log, index }) => <LogLine key={index} log={log} />)
|
||||
),
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const LogLine: React.FC<{ log: CompilationLog }> = ({ log }) => (
|
||||
<div style={styles.logLine}>
|
||||
<span style={styles.timestamp}>
|
||||
{log.timestamp.toLocaleTimeString('en-US', {
|
||||
hour12: false,
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit',
|
||||
})}
|
||||
</span>
|
||||
<span style={{ ...styles.logMessage, color: logColor(log.type) }}>
|
||||
{log.type === 'core-install' && <span style={styles.coreTag}>CORE </span>}
|
||||
{log.message}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
|
||||
function statusColor(status: 'error' | 'success' | 'running'): string {
|
||||
return status === 'error' ? '#ef5350' : status === 'success' ? '#66bb6a' : '#9aa0a6';
|
||||
}
|
||||
|
||||
function statusGlyph(status: 'error' | 'success' | 'running'): string {
|
||||
return status === 'error' ? '✕' : status === 'success' ? '✓' : '▸';
|
||||
}
|
||||
|
||||
function logColor(type: CompilationLog['type']): string {
|
||||
switch (type) {
|
||||
case 'error':
|
||||
|
|
@ -301,6 +363,40 @@ const styles: Record<string, React.CSSProperties> = {
|
|||
padding: '12px 0',
|
||||
fontFamily: 'system-ui, sans-serif',
|
||||
},
|
||||
targetGroup: {
|
||||
marginTop: 6,
|
||||
borderLeft: '2px solid #3a3a3a',
|
||||
paddingLeft: 8,
|
||||
},
|
||||
targetHeader: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: 7,
|
||||
padding: '1px 0 2px',
|
||||
},
|
||||
targetStatus: {
|
||||
fontWeight: 700,
|
||||
flexShrink: 0,
|
||||
},
|
||||
targetLabel: {
|
||||
color: '#e0e0e0',
|
||||
fontWeight: 700,
|
||||
fontSize: 11.5,
|
||||
fontFamily: 'system-ui, sans-serif',
|
||||
},
|
||||
targetKind: {
|
||||
color: '#777',
|
||||
fontSize: 9,
|
||||
fontFamily: 'system-ui, sans-serif',
|
||||
textTransform: 'uppercase' as const,
|
||||
letterSpacing: '0.5px',
|
||||
border: '1px solid #3a3a3a',
|
||||
borderRadius: 3,
|
||||
padding: '0 4px',
|
||||
},
|
||||
targetBody: {
|
||||
paddingLeft: 4,
|
||||
},
|
||||
logLine: {
|
||||
display: 'flex',
|
||||
gap: 8,
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ import { useProjectStore } from '../../store/useProjectStore';
|
|||
import { LibraryManagerModal } from '../simulator/LibraryManagerModal';
|
||||
import { InstallLibrariesModal } from '../simulator/InstallLibrariesModal';
|
||||
import { parseCompileResult } from '../../utils/compilationLogger';
|
||||
import type { CompilationLog } from '../../utils/compilationLogger';
|
||||
import type { CompilationLog, CompileTarget } from '../../utils/compilationLogger';
|
||||
import { exportToWokwiZip } from '../../utils/wokwiZip';
|
||||
import { importProjectFile, PROJECT_FILE_ACCEPT } from '../../utils/importProject';
|
||||
import { readFirmwareFile } from '../../utils/firmwareLoader';
|
||||
|
|
@ -287,38 +287,33 @@ export const EditorToolbar = ({
|
|||
const sourceC = String(props.sourceC ?? '');
|
||||
const chipJson = String(props.chipJson ?? '{}');
|
||||
let changed = false;
|
||||
// Stamp every line for this chip with its target so the console groups
|
||||
// it under its own section (alongside the boards).
|
||||
const chipTarget: CompileTarget = { id: chip.id, label: chipLabel, kind: 'chip' };
|
||||
const clog = (type: CompilationLog['type'], message: string) =>
|
||||
addLog({ timestamp: new Date(), type, message, target: chipTarget });
|
||||
|
||||
// 1. C -> WASM. Only when missing — the chip designer fills this too.
|
||||
if (!String(props.wasmBase64 ?? '') && sourceC) {
|
||||
addLog({
|
||||
timestamp: new Date(),
|
||||
type: 'info',
|
||||
message: `Compiling chip "${chipLabel}" to WASM...`,
|
||||
});
|
||||
clog('info', `Compiling chip "${chipLabel}" to WASM...`);
|
||||
try {
|
||||
const r = await compileChip(sourceC, chipJson);
|
||||
if (r.success && r.wasm_base64) {
|
||||
props.wasmBase64 = r.wasm_base64;
|
||||
changed = true;
|
||||
addLog({
|
||||
timestamp: new Date(),
|
||||
type: 'success',
|
||||
message: `Chip "${chipLabel}" compiled (${r.byte_size} B WASM).`,
|
||||
});
|
||||
clog('success', `Chip "${chipLabel}" compiled (${r.byte_size} B WASM).`);
|
||||
} else {
|
||||
addLog({
|
||||
timestamp: new Date(),
|
||||
type: 'error',
|
||||
message: `Chip "${chipLabel}" WASM compile failed: ${r.error || r.stderr || 'unknown error'}`,
|
||||
});
|
||||
clog(
|
||||
'error',
|
||||
`Chip "${chipLabel}" WASM compile failed: ${r.error || r.stderr || 'unknown error'}`,
|
||||
);
|
||||
failed++;
|
||||
}
|
||||
} catch (e) {
|
||||
addLog({
|
||||
timestamp: new Date(),
|
||||
type: 'error',
|
||||
message: `Chip "${chipLabel}" WASM compile error: ${e instanceof Error ? e.message : String(e)}`,
|
||||
});
|
||||
clog(
|
||||
'error',
|
||||
`Chip "${chipLabel}" WASM compile error: ${e instanceof Error ? e.message : String(e)}`,
|
||||
);
|
||||
failed++;
|
||||
}
|
||||
}
|
||||
|
|
@ -338,45 +333,34 @@ export const EditorToolbar = ({
|
|||
chipGroupFiles.find((f) => f.name === programFile) ??
|
||||
boardFiles.find((f) => f.name === programFile);
|
||||
if (!file) {
|
||||
addLog({
|
||||
timestamp: new Date(),
|
||||
type: 'error',
|
||||
message: `Chip "${chipLabel}": program file "${programFile}" not found in the chip's files.`,
|
||||
});
|
||||
clog('error', `Chip "${chipLabel}": program file "${programFile}" not found in the chip's files.`);
|
||||
failed++;
|
||||
} else {
|
||||
const target = targetForChip(chipJson);
|
||||
const fmt = formatForFile(programFile);
|
||||
addLog({
|
||||
timestamp: new Date(),
|
||||
type: 'info',
|
||||
message: `Assembling "${programFile}" (target=${target}, format=${fmt}) for chip "${chipLabel}"...`,
|
||||
});
|
||||
clog(
|
||||
'info',
|
||||
`Assembling "${programFile}" (target=${target}, format=${fmt}) for chip "${chipLabel}"...`,
|
||||
);
|
||||
try {
|
||||
const rr = await compileRom(file.content, target, fmt);
|
||||
if (rr.success && rr.rom_base64) {
|
||||
props.romBytes = rr.rom_base64;
|
||||
props.programFile = programFile;
|
||||
changed = true;
|
||||
addLog({
|
||||
timestamp: new Date(),
|
||||
type: 'success',
|
||||
message: `ROM ready: ${rr.byte_size} B injected into "${chipLabel}".`,
|
||||
});
|
||||
clog('success', `ROM ready: ${rr.byte_size} B injected into "${chipLabel}".`);
|
||||
} else {
|
||||
addLog({
|
||||
timestamp: new Date(),
|
||||
type: 'error',
|
||||
message: `ROM compile failed for "${programFile}": ${rr.error || rr.stderr || 'unknown error'}`,
|
||||
});
|
||||
clog(
|
||||
'error',
|
||||
`ROM compile failed for "${programFile}": ${rr.error || rr.stderr || 'unknown error'}`,
|
||||
);
|
||||
failed++;
|
||||
}
|
||||
} catch (e) {
|
||||
addLog({
|
||||
timestamp: new Date(),
|
||||
type: 'error',
|
||||
message: `ROM compile error for "${programFile}": ${e instanceof Error ? e.message : String(e)}`,
|
||||
});
|
||||
clog(
|
||||
'error',
|
||||
`ROM compile error for "${programFile}": ${e instanceof Error ? e.message : String(e)}`,
|
||||
);
|
||||
failed++;
|
||||
}
|
||||
}
|
||||
|
|
@ -432,14 +416,18 @@ export const EditorToolbar = ({
|
|||
// ── End custom-chip preparation ─────────────────────────────────────
|
||||
|
||||
const kind = activeBoard?.boardKind;
|
||||
// The active board's console target, defined up front so EVERY board path
|
||||
// (Pi, MicroPython, arduino-cli, errors) groups its lines under one section.
|
||||
const boardLabel = activeBoard ? boardDisplayName(activeBoard) : 'Unknown';
|
||||
const boardTarget: CompileTarget | undefined = activeBoardId
|
||||
? { id: activeBoardId, label: boardLabel, kind: 'board' }
|
||||
: undefined;
|
||||
const blog = (type: CompilationLog['type'], message: string) =>
|
||||
addLog({ timestamp: new Date(), type, message, target: boardTarget });
|
||||
|
||||
// Raspberry Pi 3B doesn't need arduino-cli compilation
|
||||
if (isPiBoardKind(kind)) {
|
||||
addLog({
|
||||
timestamp: new Date(),
|
||||
type: 'info',
|
||||
message: 'Raspberry Pi 3B: no compilation needed — run Python scripts directly.',
|
||||
});
|
||||
blog('info', 'Raspberry Pi 3B: no compilation needed — run Python scripts directly.');
|
||||
setMessage({ type: 'success', text: 'Ready (no compilation needed)' });
|
||||
setCompiling(false);
|
||||
return;
|
||||
|
|
@ -447,24 +435,16 @@ export const EditorToolbar = ({
|
|||
|
||||
// MicroPython mode — no backend compilation needed
|
||||
if (activeBoard?.languageMode === 'micropython' && activeBoardId) {
|
||||
addLog({
|
||||
timestamp: new Date(),
|
||||
type: 'info',
|
||||
message: 'MicroPython: loading firmware and user files...',
|
||||
});
|
||||
blog('info', 'MicroPython: loading firmware and user files...');
|
||||
try {
|
||||
const groupFiles = useEditorStore.getState().getGroupFiles(activeBoard.activeFileGroupId);
|
||||
const pyFiles = groupFiles.map((f) => ({ name: f.name, content: f.content }));
|
||||
await loadMicroPythonProgram(activeBoardId, pyFiles);
|
||||
addLog({
|
||||
timestamp: new Date(),
|
||||
type: 'success',
|
||||
message: 'MicroPython firmware loaded successfully',
|
||||
});
|
||||
blog('success', 'MicroPython firmware loaded successfully');
|
||||
setMessage({ type: 'success', text: 'MicroPython ready' });
|
||||
} catch (err) {
|
||||
const errMsg = err instanceof Error ? err.message : 'Failed to load MicroPython';
|
||||
addLog({ timestamp: new Date(), type: 'error', message: errMsg });
|
||||
blog('error', errMsg);
|
||||
setMessage({ type: 'error', text: errMsg });
|
||||
} finally {
|
||||
setCompiling(false);
|
||||
|
|
@ -473,20 +453,15 @@ export const EditorToolbar = ({
|
|||
}
|
||||
|
||||
const fqbn = kind ? BOARD_KIND_FQBN[kind] : null;
|
||||
const boardLabel = activeBoard ? boardDisplayName(activeBoard) : 'Unknown';
|
||||
|
||||
if (!fqbn) {
|
||||
addLog({ timestamp: new Date(), type: 'error', message: `No FQBN for board kind: ${kind}` });
|
||||
blog('error', `No FQBN for board kind: ${kind}`);
|
||||
setMessage({ type: 'error', text: 'Unknown board' });
|
||||
setCompiling(false);
|
||||
return;
|
||||
}
|
||||
|
||||
addLog({
|
||||
timestamp: new Date(),
|
||||
type: 'info',
|
||||
message: `Starting compilation for ${boardLabel} (${fqbn})...`,
|
||||
});
|
||||
blog('info', `Starting compilation for ${boardLabel} (${fqbn})...`);
|
||||
|
||||
try {
|
||||
const groupFiles = activeBoard?.activeFileGroupId
|
||||
|
|
@ -524,6 +499,7 @@ export const EditorToolbar = ({
|
|||
timestamp: now,
|
||||
type: 'info' as const,
|
||||
message: line,
|
||||
target: boardTarget,
|
||||
})),
|
||||
]);
|
||||
},
|
||||
|
|
@ -539,7 +515,7 @@ export const EditorToolbar = ({
|
|||
// the live stream — parseCompileResult highlights FAILED blocks and
|
||||
// tags compiler errors with type='error', which the console uses for
|
||||
// colour + the auto-switch-to-errors filter.
|
||||
const resultLogs = parseCompileResult(result, boardLabel);
|
||||
const resultLogs = parseCompileResult(result, boardLabel, boardTarget);
|
||||
setCompileLogs((prev: CompilationLog[]) => [...prev, ...resultLogs]);
|
||||
|
||||
if (result.success) {
|
||||
|
|
@ -571,7 +547,7 @@ export const EditorToolbar = ({
|
|||
}
|
||||
} catch (err) {
|
||||
const errMsg = err instanceof Error ? err.message : 'Compile failed';
|
||||
addLog({ timestamp: new Date(), type: 'error', message: errMsg });
|
||||
blog('error', errMsg);
|
||||
setMessage({ type: 'error', text: errMsg });
|
||||
} finally {
|
||||
setCompiling(false);
|
||||
|
|
@ -747,23 +723,22 @@ export const EditorToolbar = ({
|
|||
|
||||
setCompiling(true);
|
||||
setMessage(null);
|
||||
addLog({
|
||||
timestamp: new Date(),
|
||||
type: 'info',
|
||||
message: 'MicroPython: loading firmware and user files...',
|
||||
});
|
||||
const mpyTarget: CompileTarget = {
|
||||
id: activeBoardId,
|
||||
label: boardDisplayName(board),
|
||||
kind: 'board',
|
||||
};
|
||||
const mlog = (type: CompilationLog['type'], message: string) =>
|
||||
addLog({ timestamp: new Date(), type, message, target: mpyTarget });
|
||||
mlog('info', 'MicroPython: loading firmware and user files...');
|
||||
try {
|
||||
const groupFiles = useEditorStore.getState().getGroupFiles(board.activeFileGroupId);
|
||||
const pyFiles = groupFiles.map((f) => ({ name: f.name, content: f.content }));
|
||||
await loadMicroPythonProgram(activeBoardId, pyFiles);
|
||||
addLog({
|
||||
timestamp: new Date(),
|
||||
type: 'success',
|
||||
message: 'MicroPython firmware loaded',
|
||||
});
|
||||
mlog('success', 'MicroPython firmware loaded');
|
||||
} catch (err) {
|
||||
const errMsg = err instanceof Error ? err.message : 'Failed to load MicroPython';
|
||||
addLog({ timestamp: new Date(), type: 'error', message: errMsg });
|
||||
mlog('error', errMsg);
|
||||
setMessage({ type: 'error', text: errMsg });
|
||||
setCompiling(false);
|
||||
return;
|
||||
|
|
@ -955,29 +930,25 @@ export const EditorToolbar = ({
|
|||
|
||||
for (const board of boardsList) {
|
||||
const label = boardDisplayName(board);
|
||||
// Stamp this board's lines so the console groups them under its section.
|
||||
const boardTarget: CompileTarget = { id: board.id, label, kind: 'board' };
|
||||
const blog = (type: CompilationLog['type'], message: string) =>
|
||||
addLog({ timestamp: new Date(), type, message, target: boardTarget });
|
||||
|
||||
if (isPiBoardKind(board.boardKind)) {
|
||||
addLog({
|
||||
timestamp: new Date(),
|
||||
type: 'info',
|
||||
message: `${label}: skipped (no compilation needed)`,
|
||||
});
|
||||
blog('info', 'skipped (no compilation needed)');
|
||||
ok++;
|
||||
continue;
|
||||
}
|
||||
|
||||
const fqbn = BOARD_KIND_FQBN[board.boardKind];
|
||||
if (!fqbn) {
|
||||
addLog({
|
||||
timestamp: new Date(),
|
||||
type: 'error',
|
||||
message: `${label}: no FQBN configured`,
|
||||
});
|
||||
blog('error', 'no FQBN configured');
|
||||
boardFailed++;
|
||||
continue;
|
||||
}
|
||||
|
||||
addLog({ timestamp: new Date(), type: 'info', message: `${label}: compiling...` });
|
||||
blog('info', 'compiling...');
|
||||
|
||||
try {
|
||||
const groupFiles = useEditorStore.getState().getGroupFiles(board.activeFileGroupId);
|
||||
|
|
@ -1000,17 +971,19 @@ export const EditorToolbar = ({
|
|||
const now = new Date();
|
||||
setCompileLogs((prev: CompilationLog[]) => [
|
||||
...prev,
|
||||
// No `${label}: ` prefix — the target section header carries it.
|
||||
...newLines.map((line) => ({
|
||||
timestamp: now,
|
||||
type: 'info' as const,
|
||||
message: `${label}: ${line}`,
|
||||
message: line,
|
||||
target: boardTarget,
|
||||
})),
|
||||
]);
|
||||
},
|
||||
{ boardOptions: board.boardOptions, spiffsFiles: board.spiffsFiles },
|
||||
);
|
||||
|
||||
const resultLogs = parseCompileResult(result, label);
|
||||
const resultLogs = parseCompileResult(result, label, boardTarget);
|
||||
setCompileLogs((prev: CompilationLog[]) => [...prev, ...resultLogs]);
|
||||
|
||||
if (result.success) {
|
||||
|
|
@ -1026,11 +999,7 @@ export const EditorToolbar = ({
|
|||
boardFailed++;
|
||||
}
|
||||
} catch (err) {
|
||||
addLog({
|
||||
timestamp: new Date(),
|
||||
type: 'error',
|
||||
message: `${label}: ${err instanceof Error ? err.message : String(err)}`,
|
||||
});
|
||||
blog('error', err instanceof Error ? err.message : String(err));
|
||||
boardFailed++;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,13 +4,28 @@
|
|||
|
||||
import type { CompileResult } from '../services/compilation';
|
||||
|
||||
/** Which run target a log line belongs to — lets the console group output by
|
||||
* board / chip, the way multiple Arduinos already stream. Optional: lines with
|
||||
* no target (e.g. "Compiling all targets...", "Done") render as plain
|
||||
* narration. */
|
||||
export interface CompileTarget {
|
||||
id: string;
|
||||
label: string;
|
||||
kind: 'board' | 'chip';
|
||||
}
|
||||
|
||||
export interface CompilationLog {
|
||||
timestamp: Date;
|
||||
type: 'info' | 'success' | 'error' | 'warning' | 'core-install';
|
||||
message: string;
|
||||
target?: CompileTarget;
|
||||
}
|
||||
|
||||
export function parseCompileResult(result: CompileResult, board: string): CompilationLog[] {
|
||||
export function parseCompileResult(
|
||||
result: CompileResult,
|
||||
board: string,
|
||||
target?: CompileTarget,
|
||||
): CompilationLog[] {
|
||||
const logs: CompilationLog[] = [];
|
||||
const now = new Date();
|
||||
|
||||
|
|
@ -88,5 +103,5 @@ export function parseCompileResult(result: CompileResult, board: string): Compil
|
|||
logs.push({ timestamp: now, type: 'error', message: `✕ ${errorMsg}` });
|
||||
}
|
||||
|
||||
return logs;
|
||||
return target ? logs.map((l) => ({ ...l, target })) : logs;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue