SQLite Schema Documenter
Convert SQL CREATE statements to Markdown documentation.
Generating preview...
No schema to preview.
"; return; } // 1. Extract Tables using Regex // This regex looks for CREATE TABLE [name] ( [content] ); const tableRegex = /CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?["`]?(\w+)["`]?\s*\(([\s\S]*?)\);/gim; let match; const tables = []; while ((match = tableRegex.exec(rawSql)) !== null) { const tableName = match[1]; const body = match[2]; const columns = []; // Split body by comma, but respect parentheses (for composite keys/constraints) // Simple split approach (works for standard SQLite dumps) const lines = body.split(/,\r?\n|,\n/); lines.forEach(line => { line = line.trim(); if (!line) return; // Check if it's a constraint line (FOREIGN KEY, PRIMARY KEY at table level) if (line.toUpperCase().startsWith('FOREIGN KEY') || line.toUpperCase().startsWith('PRIMARY KEY') || line.toUpperCase().startsWith('CONSTRAINT')) { // Add as a special note or separate section? For now, let's ignore table-level constraints in column list to keep it clean, // OR add them as a 'Constraint' row. // Let's try to parse basic columns: NAME TYPE CONSTRAINTS return; } // Basic Column Parse: "name type constraints" // Regex to capture first word (name), second word (type), rest (attributes) const colMatch = line.match(/["`]?(\w+)["`]?\s+(\w+)([\s\S]*)/); if (colMatch) { columns.push({ name: colMatch[1], type: colMatch[2], attribs: colMatch[3].replace(/,$/, '').trim() // remove trailing comma }); } }); tables.push({ name: tableName, columns: columns }); } // 2. Build Markdown let md = `# ${projectName}\n\n`; md += `> Generated on ${new Date().toLocaleDateString()}\n\n`; if (includeToc && tables.length > 0) { md += `## Table of Contents\n`; tables.forEach(t => { md += `- [${t.name}](#${t.name.toLowerCase()})\n`; }); md += `\n---\n\n`; } if (tables.length === 0) { md += `*No tables found. Ensure your SQL uses standard `CREATE TABLE table_name (...);` syntax.*`; } else { tables.forEach(t => { md += `## ${t.name}\n\n`; md += `| Column | Type | Attributes |\n`; md += `| :--- | :--- | :--- |\n`; t.columns.forEach(c => { // Escape pipes for markdown table const safeAttribs = c.attribs.replace(/\|/g, '\\|'); md += `| **${c.name}** | \`${c.type}\` | ${safeAttribs} |\n`; }); md += `\n[Back to top](#table-of-contents)\n\n`; }); } // 3. Render Output const codeBlock = document.getElementById('sqldoc-md-code'); codeBlock.textContent = md; Prism.highlightElement(codeBlock); // 4. Render Live Preview const previewArea = document.getElementById('sqldoc-pdf-area'); previewArea.innerHTML = marked.parse(md); } // --- UTILS --- function sqldocCopyToClipboard() { const code = document.getElementById('sqldoc-md-code').innerText; navigator.clipboard.writeText(code).then(() => { const btn = document.querySelector('#tab-markdown .sqldoc-btn-outline'); const originalText = btn.innerHTML; btn.innerHTML = ' Copied!'; setTimeout(() => btn.innerHTML = originalText, 2000); }); } // PDF Export function sqldocGeneratePDF() { // Ensure preview is fresh sqldocParse(); const element = document.getElementById('sqldoc-pdf-area'); const projectName = document.getElementById('cfg-project').value || "Schema"; const filename = projectName.replace(/[^a-z0-9]/gi, '_').toLowerCase() + "_docs.pdf"; const opt = { margin: [10, 10], filename: filename, image: { type: 'jpeg', quality: 0.98 }, html2canvas: { scale: 2, useCORS: true, background: '#ffffff' }, // White bg for PDF readability jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' }, pagebreak: { mode: ['avoid-all', 'css', 'legacy'] } }; // Temporarily change styles for PDF generation (Light mode logic) const originalColor = element.style.color; const originalBg = element.style.background; element.style.color = "#000000"; element.style.background = "#ffffff"; // Fix table headers for PDF const ths = element.querySelectorAll('th'); ths.forEach(th => { th.style.backgroundColor = '#e2e8f0'; th.style.color = '#000'; }); html2pdf().set(opt).from(element).save().then(() => { // Revert styles element.style.color = ""; element.style.background = ""; ths.forEach(th => { th.style.backgroundColor = ""; th.style.color = ""; }); }); }