(function() { const textarea = document.getElementById('yaml-input'); const errorEl = document.getElementById('error'); const metaEl = document.getElementById('meta'); const renderBtn = document.getElementById('render-btn'); const editor = CodeMirror.fromTextArea(textarea, { mode: 'yaml', lineNumbers: true, lineWrapping: true, tabSize: 2, indentUnit: 2, }); const sample = `openapi: 3.0.0 info: title: Sample API version: 1.0.0 paths: /api/test/bla: get: summary: Get bla responses: '200': description: OK /api/test/foo: post: summary: Create foo responses: '201': description: Created /api/users/{id}: get: summary: Get user responses: '200': { description: OK } `; editor.setValue(sample); function selectWholeLine(lineNumber) { const lineText = editor.getLine(lineNumber) || ''; const from = { line: lineNumber, ch: 0 }; const to = { line: lineNumber, ch: lineText.length }; editor.setSelection(from, to); editor.scrollIntoView({ from, to }, 100); editor.focus(); } function jumpToEndpointInYaml(path) { const lineCount = editor.lineCount(); const target = `${path}:`; for (let i = 0; i < lineCount; i++) { const line = editor.getLine(i); if (!line) continue; if (line.trimStart().startsWith(target)) { selectWholeLine(i); return true; } } return false; } async function parseAndRender() { errorEl.textContent = ''; metaEl.textContent = ''; const yamlText = editor.getValue(); try { const res = await fetch('/api/parse', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ yaml: yamlText }) }); const data = await res.json(); if (!res.ok) { throw new Error(data && data.error ? data.error : 'Failed to parse'); } const { graph, info } = data; if (info && (info.title || info.version)) { const title = info.title || 'Untitled'; const version = info.version ? ` v${info.version}` : ''; metaEl.textContent = `${title}${version}`; } const endpoints = graph.endpoints || []; function onNodeClick(segmentId) { const match = endpoints.find(ep => { const parts = (ep.path || '').split('/').filter(Boolean); return parts.includes(segmentId); }); if (match) { if (!jumpToEndpointInYaml(match.path)) { // Fallback: best-effort contains check const lineCount = editor.lineCount(); for (let i = 0; i < lineCount; i++) { const line = editor.getLine(i) || ''; if (line.includes(match.path)) { selectWholeLine(i); break; } } } } } renderGraph('#graph', graph, { onNodeClick }); } catch (e) { errorEl.textContent = e.message || String(e); } } renderBtn.addEventListener('click', parseAndRender); // initial render parseAndRender(); })();