From f246e1e438d26ec853cb277090de2a6f3741dabd Mon Sep 17 00:00:00 2001 From: Dicken Date: Sat, 30 May 2026 00:34:36 +0200 Subject: [PATCH] =?UTF-8?q?YAML:=20dreistufiger=20Fix=20-=20Unit=20?= =?UTF-8?q?=E2=86=92=20Stack=20=E2=86=92=20best-effort?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/tools/devtools.jsx | 94 ++++++++++++++++++--------------- 1 file changed, 50 insertions(+), 44 deletions(-) diff --git a/frontend/src/tools/devtools.jsx b/frontend/src/tools/devtools.jsx index da48e23..0710b33 100644 --- a/frontend/src/tools/devtools.jsx +++ b/frontend/src/tools/devtools.jsx @@ -120,40 +120,49 @@ function collectPaths(data, path='root', paths=[]) { return paths; } -// ── YAML Auto-Fix: Stack-basierter Strukturerhalter ────────────────────────── -function fixYamlIndentation(text) { +// ── YAML Auto-Fix Stufe 1: Einheits-Normalisierung (kleine Fehler) ──────────── +function fixByUnit(text) { + const lines = text.split('\n').map(l => l.replace(/\t/g, ' ')); + const indents = lines + .filter(l => l.trim() && !l.trim().startsWith('#')) + .map(l => l.search(/\S/)) + .filter(n => n > 0); + if (!indents.length) return text; + const unit = Math.min(...indents); + if (unit === 2) return lines.join('\n'); // bereits 2-space + return lines.map(line => { + if (!line.trim()) return ''; + if (line.trim().startsWith('#')) return line.trimEnd(); + const spaces = line.search(/\S/); + if (spaces <= 0) return line.trimEnd(); + return ' '.repeat(Math.round(spaces / unit)) + line.trimStart().trimEnd(); + }).join('\n'); +} + +// ── YAML Auto-Fix Stufe 2: Stack-basiert (starke Schäden) ──────────────────── +function fixByStack(text) { const lines = text.split('\n').map(l => l.replace(/\t/g, ' ')); const stack = [{ indent: -1, depth: -1 }]; const result = []; - for (const line of lines) { if (!line.trim()) { result.push(''); continue; } - const indent = line.search(/\S/); const content = line.trim(); - if (content.startsWith('#')) { result.push(' '.repeat(Math.max(0, stack[stack.length-1].depth + 1)) + content); continue; } - - // Pop stack-Einträge die >= aktuelle Einrückung haben - while (stack.length > 1 && stack[stack.length-1].indent >= indent) { - stack.pop(); - } - + while (stack.length > 1 && stack[stack.length-1].indent >= indent) stack.pop(); const depth = stack[stack.length-1].depth + 1; stack.push({ indent, depth }); result.push(' '.repeat(depth) + content); } - return result.join('\n'); } -// Versucht einen lesbaren Fehler aus dem js-yaml Fehler zu bauen function shortError(e) { const first = e.message.split('\n')[0]; - return first.length > 120 ? first.slice(0,120)+'…' : first; + return first.length > 120 ? first.slice(0, 120) + '…' : first; } // ── YAML Tool ───────────────────────────────────────────────────────────────── @@ -170,40 +179,37 @@ function YamlTool({ mobile }) { const process = useCallback((text) => { if (!text.trim()) { setParsed(null); setFormatted(''); setError(''); setWarning(''); return; } - let obj, parseError = null; + const tryParse = (t) => { try { return { obj: jsyaml.load(t), err: null }; } catch(e) { return { obj: null, err: e }; } }; - // Versuch 1: direkt parsen - try { obj = jsyaml.load(text); } - catch(e) { parseError = e; } - - // Versuch 2: Auto-Fix, dann nochmal - if (parseError) { - const fixed = fixYamlIndentation(text); - try { - obj = jsyaml.load(fixed); - setWarning(`⚠ Einrückung automatisch korrigiert – bitte Ergebnis prüfen`); - } catch(e2) { - // Auch nach Fix nicht parsebar → best-effort Text trotzdem anzeigen - setError(shortError(parseError)); - setWarning('Struktur zu stark beschädigt – nur Einrückung wurde normalisiert. Bitte manuell korrigieren.'); - setParsed(null); - setFormatted(fixed); // zeige korrigierten Text zum manuellen Nachbessern - return; - } - } else { - setWarning(''); + // Stufe 1: direkt + const r1 = tryParse(text); + if (!r1.err) { + setParsed(r1.obj); setFormatted(jsyaml.dump(r1.obj, {indent:2,lineWidth:-1,noRefs:true})); + setError(''); setWarning(''); setCollapsed(new Set()); return; } - try { - setParsed(obj); - setFormatted(jsyaml.dump(obj, { indent:2, lineWidth:-1, noRefs:true })); - setError(''); - setCollapsed(new Set()); - } catch(e) { - setError(e.message); - setParsed(null); setFormatted(''); + // Stufe 2: Unit-Normalisierung (für kleine Fehler wie 4-space statt 2-space) + const fixed1 = fixByUnit(text); + const r2 = tryParse(fixed1); + if (!r2.err) { + setParsed(r2.obj); setFormatted(jsyaml.dump(r2.obj, {indent:2,lineWidth:-1,noRefs:true})); + setWarning('✓ Einrückung normalisiert'); setError(''); setCollapsed(new Set()); return; } - },[]); + + // Stufe 3: Stack-Fix (für stärker beschädigte Struktur) + const fixed2 = fixByStack(text); + const r3 = tryParse(fixed2); + if (!r3.err) { + setParsed(r3.obj); setFormatted(jsyaml.dump(r3.obj, {indent:2,lineWidth:-1,noRefs:true})); + setWarning('⚠ Einrückung stark korrigiert – bitte Ergebnis prüfen'); setError(''); setCollapsed(new Set()); return; + } + + // Stufe 4: best-effort – zeige korrigierten Text zum manuellen Nachbessern + setError(shortError(r1.err)); + setWarning('Struktur nicht automatisch reparierbar – normalisierter Text zum manuellen Korrigieren:'); + setParsed(null); + setFormatted(fixed2); + }, []); const onInput = v => { setInput(v); process(v); };