diff --git a/frontend/src/tools/devtools.jsx b/frontend/src/tools/devtools.jsx index 5bdcd32..d8de6ed 100644 --- a/frontend/src/tools/devtools.jsx +++ b/frontend/src/tools/devtools.jsx @@ -122,45 +122,29 @@ function collectPaths(data, path='root', paths=[]) { // ── YAML Auto-Fix: normalisiert Einrückung bevor js-yaml parst ─────────────── function fixYamlIndentation(text) { - // Normalisiert Tabs → Spaces, erkennt Einrückungs-Inkonsistenz - // Strategie: Einrückung auf Basis des ersten vorkommenden Levels normalisieren const lines = text.split('\n'); - const fixed = []; - - for (const line of lines) { - // Tabs zu 2 Spaces - const noTabs = line.replace(/\t/g, ' '); - fixed.push(noTabs); - } - - // Normalisiere die Einrückungslevel auf gerade 2-Vielfache - const result = []; - const indentStack = [0]; // Stack der gültigen Einrück-Level - - for (const line of fixed) { - if (!line.trim()) { result.push(''); continue; } - if (line.trim().startsWith('#')) { result.push(line); continue; } - - const current = line.search(/\S/); - const content = line.trimStart(); - - // Finde den nächsten passenden Level im Stack - let level = indentStack.length - 1; - while (level > 0 && indentStack[level] > current) level--; - - if (current > indentStack[level]) { - // Neue Einrückungstiefe - indentStack.splice(level + 1); // alles nach level entfernen - indentStack.push(current); - level = indentStack.length - 1; - } - - // Normalize: depth * 2 spaces - const normalizedIndent = ' '.repeat(level); - result.push(normalizedIndent + content); - } - - return result.join('\n'); + + // 1. Tabs → Spaces (4 oder 2) + const detabbed = lines.map(l => l.replace(/\t/g, ' ')); + + // 2. Finde die kleinste vorkommende Einrückung > 0 (das ist die Einheit) + const indents = detabbed + .filter(l => l.trim() && !l.trim().startsWith('#')) + .map(l => l.search(/\S/)) + .filter(n => n > 0); + const unit = indents.length ? Math.min(...indents) : 2; + + // 3. Remap: jede Einrückung → Niveau * 2 Spaces + const remapped = detabbed.map(line => { + if (!line.trim()) return ''; + if (line.trim().startsWith('#')) return line.trimEnd(); + const spaces = line.search(/\S/); + if (spaces <= 0) return line.trimEnd(); + const level = Math.round(spaces / unit); + return ' '.repeat(level) + line.trimStart().trimEnd(); + }); + + return remapped.join('\n'); } // ── YAML Tool ───────────────────────────────────────────────────────────────── @@ -177,29 +161,37 @@ function YamlTool({ mobile }) { const process = useCallback((text) => { if (!text.trim()) { setParsed(null); setFormatted(''); setError(''); setWarning(''); return; } - // Erste Versuch: direkt parsen - try { - const obj = jsyaml.load(text); - setParsed(obj); - setFormatted(jsyaml.dump(obj, { indent:2, lineWidth:-1, noRefs:true })); - setError(''); setWarning(''); - setCollapsed(new Set()); - return; - } catch(e) { - // Zweiter Versuch: Auto-Fix und dann parsen + let obj, parseError = null; + + // Versuch 1: direkt parsen + try { obj = jsyaml.load(text); } + catch(e) { parseError = e; } + + // Versuch 2: wenn Fehler → Auto-Fix, dann nochmal + if (parseError) { try { const fixed = fixYamlIndentation(text); - const obj = jsyaml.load(fixed); - setParsed(obj); - setFormatted(jsyaml.dump(obj, { indent:2, lineWidth:-1, noRefs:true })); - setWarning(`⚠ Einrückung automatisch korrigiert: ${e.message.split('\n')[0]}`); - setError(''); - setCollapsed(new Set()); + obj = jsyaml.load(fixed); + setWarning(`⚠ Einrückung automatisch korrigiert: ${parseError.message.split('\n')[0]}`); } catch(e2) { - setError(e.message); + // Fix hat auch nicht geholfen – originalen Fehler zeigen + setError(parseError.message); setWarning(''); setParsed(null); setFormatted(''); + return; } + } else { + setWarning(''); + } + + 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(''); } },[]);