YAML: Auto-Fix bei Einrückungsfehlern; Skizze: Baustellen-Badge

This commit is contained in:
2026-05-29 19:38:40 +02:00
parent a1b00a0f0d
commit f26d898088
2 changed files with 87 additions and 9 deletions

View File

@@ -120,27 +120,86 @@ function collectPaths(data, path='root', paths=[]) {
return 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');
}
// ── YAML Tool ─────────────────────────────────────────────────────────────────
function YamlTool({ mobile }) {
const [input, setInput] = useState('');
const [parsed, setParsed] = useState(null);
const [formatted,setFormatted]= useState('');
const [error, setError] = useState('');
const [warning, setWarning] = useState('');
const [copied, setCopied] = useState(false);
const [view, setView] = useState('tree'); // 'tree' | 'raw'
const [view, setView] = useState('tree');
const [collapsed,setCollapsed]= useState(new Set());
const process = useCallback((text) => {
if (!text.trim()) { setParsed(null); setFormatted(''); setError(''); return; }
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('');
setCollapsed(new Set()); // reset collapsed
setError(''); setWarning('');
setCollapsed(new Set());
return;
} catch(e) {
setError(e.message);
setParsed(null); setFormatted('');
// Zweiter Versuch: Auto-Fix und dann parsen
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());
} catch(e2) {
setError(e.message);
setWarning('');
setParsed(null); setFormatted('');
}
}
},[]);
@@ -214,7 +273,15 @@ function YamlTool({ mobile }) {
borderRadius:8,padding:14,color:'#ff6b9d',fontFamily:'monospace',fontSize:11,lineHeight:1.7}}>
{error}
</div>
) : view==='raw' ? (
) : (<>
{warning && (
<div style={{background:'rgba(255,230,109,0.07)',border:'1px solid rgba(255,230,109,0.2)',
borderRadius:7,padding:'7px 12px',color:'#ffe66d',fontFamily:'monospace',
fontSize:10,lineHeight:1.6,marginBottom:8}}>
{warning}
</div>
)}
{view==='raw' ? (
<pre style={{margin:0,padding:14,minHeight:200,background:'rgba(0,0,0,0.35)',
border:'1px solid rgba(255,255,255,0.07)',borderRadius:8,
color:formatted?'#d4e6b5':'rgba(255,255,255,0.15)',
@@ -236,6 +303,7 @@ function YamlTool({ mobile }) {
YAML eingeben wird live formatiert
</div>
)}
</>)}
</div>
</div>
<div style={{color:'rgba(255,255,255,0.15)',fontFamily:'monospace',fontSize:9}}>