Generate-ReferenceHTML.ps1
|
<# .SYNOPSIS Generates a complete HTML reference with functions, descriptions, parameters, and examples. .DESCRIPTION Reads all .ps1 files from the Public directory, extracts function metadata including: - Function name - Synopsis (description) - Parameters with types - Examples (all .EXAMPLE blocks) Output: sqmSQLTool-reference-full.html (standalone HTML with search, sidebar, dark theme) #> $sourcePath = Split-Path $PSCommandPath $publicDir = Join-Path $sourcePath "Public" $outputFile = Join-Path $sourcePath "Docs\sqmSQLTool-reference-full.html" if (-not (Test-Path $publicDir)) { Write-Error "Public directory not found: $publicDir" exit 1 } $functions = @() Get-ChildItem $publicDir -Filter "*.ps1" | ForEach-Object { $content = Get-Content $_.FullName -Raw # Extract function name if ($content -match 'function\s+([\w-]+)\s*\{') { $funcName = $matches[1] # Extract SYNOPSIS $synopsis = "" if ($content -match '\.SYNOPSIS\s*\r?\n\s*(.+?)(?:\r?\n\s*\.|$)') { $synopsis = $matches[1].Trim() } # Extract all PARAMETERS $params = @() [regex]::Matches($content, '\[\s*Parameter[^\]]*\]\s*(?:\[[^\]]+\]\s*)*\$(\w+)') | ForEach-Object { $params += $_.Groups[1].Value } # Extract all EXAMPLES - split by .EXAMPLE blocks $examples = @() if ($content -match '<#([\s\S]*?)#>') { $helpBlock = $matches[1] # Split on .EXAMPLE $parts = $helpBlock -split '\.EXAMPLE\s*\r?\n' # Skip first part (not an example), process rest for ($i = 1; $i -lt $parts.Count; $i++) { $exampleText = $parts[$i] # Take everything until next .SECTION (like .NOTES, .DESCRIPTION, etc) if ($exampleText -match '^([\s\S]*?)(?=\n\s*\.\w+|$)') { $exampleText = $matches[1].Trim() if ($exampleText -and $exampleText.Length -gt 10) { $examples += $exampleText } } } } $functions += [PSCustomObject]@{ Name = $funcName Synopsis = $synopsis Params = $params Examples = $examples } } } $functions = $functions | Sort-Object Name # Create functions JSON $functionsJson = $functions | ConvertTo-Json -Depth 10 $html = @" <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>sqmSQLTool - Command Reference</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif; background-color: #060f20; color: #e2e8f0; line-height: 1.6; } .psdb-st { display: flex; min-height: 100vh; } .psdb-st-sidebar { width: 280px; background-color: #0b1e3d; padding: 2rem 0; border-right: 1px solid #1e3a5f; position: fixed; height: 100vh; overflow-y: auto; top: 0; left: 0; } .psdb-st-sidebar-title { padding: 0 1.5rem; margin-bottom: 1.5rem; font-size: 0.875rem; font-weight: 600; color: #94a8c0; text-transform: uppercase; letter-spacing: 0.05em; } .psdb-st-sidebar-search { padding: 0 1rem 1rem; margin-bottom: 1.5rem; } .psdb-st-sidebar-search input { width: 100%; padding: 0.5rem 0.75rem; background-color: #051329; border: 1px solid #1e3a5f; border-radius: 0.375rem; color: #e2e8f0; font-size: 0.875rem; } .psdb-st-sidebar-search input:focus { outline: none; border-color: #2e86c1; background-color: #051329; } .psdb-st-sidebar-list { list-style: none; padding: 0 0.5rem; } .psdb-st-sidebar-item { margin-bottom: 0.25rem; } .psdb-st-sidebar-link { display: block; padding: 0.5rem 1rem; color: #94a8c0; text-decoration: none; border-radius: 0.375rem; font-size: 0.875rem; transition: all 0.2s ease; } .psdb-st-sidebar-link:hover { background-color: #1e3a5f; color: #e2e8f0; } .psdb-st-sidebar-link.active { background-color: #2e86c1; color: #ffffff; font-weight: 600; } .psdb-st-content { flex: 1; margin-left: 280px; padding: 2rem 3rem; max-width: 1400px; margin-right: auto; } .psdb-st-header { margin-bottom: 3rem; } .psdb-st-h1 { font-size: 2.5rem; font-weight: 700; margin-bottom: 0.5rem; background: linear-gradient(160deg, #2e86c1 0%, #5dade2 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; } .psdb-st-subtitle { color: #94a8c0; font-size: 1rem; } .psdb-st-functions { display: grid; grid-template-columns: 1fr; gap: 2rem; } .psdb-st-card { background-color: #0b1e3d; border: 1px solid #1e3a5f; border-radius: 0.5rem; padding: 2rem; transition: all 0.2s ease; } .psdb-st-card:hover { border-color: #2e86c1; box-shadow: 0 0 20px rgba(46, 134, 193, 0.1); } .psdb-st-card-title { font-size: 1.25rem; font-weight: 600; color: #5dade2; margin-bottom: 0.75rem; font-family: 'Courier New', monospace; } .psdb-st-card-synopsis { color: #e2e8f0; margin-bottom: 1rem; line-height: 1.6; } .psdb-st-section-title { font-size: 0.875rem; font-weight: 700; color: #94a8c0; text-transform: uppercase; letter-spacing: 0.05em; margin-top: 1rem; margin-bottom: 0.5rem; } .psdb-st-params { list-style: none; margin-bottom: 1rem; } .psdb-st-param { padding: 0.5rem 0; color: #94a8c0; font-family: 'Courier New', monospace; font-size: 0.875rem; margin-left: 0; } .psdb-st-param::before { content: '→ '; color: #2e86c1; margin-right: 0.5rem; } .psdb-st-examples { margin-top: 1rem; } .psdb-st-example { background-color: #051329; border-left: 3px solid #2e86c1; padding: 1rem; margin-bottom: 0.75rem; border-radius: 0.25rem; font-family: 'Courier New', monospace; font-size: 0.875rem; color: #94a8c0; white-space: pre-wrap; word-wrap: break-word; line-height: 1.4; } .psdb-st-no-data { color: #94a8c0; font-style: italic; } @media (max-width: 1024px) { .psdb-st-sidebar { width: 250px; } .psdb-st-content { margin-left: 250px; padding: 1.5rem 2rem; } } @media (max-width: 768px) { .psdb-st { flex-direction: column; } .psdb-st-sidebar { position: relative; width: 100%; height: auto; border-right: none; border-bottom: 1px solid #1e3a5f; } .psdb-st-content { margin-left: 0; padding: 1rem; } .psdb-st-h1 { font-size: 1.75rem; } } .hidden { display: none; } </style> </head> <body> <div class="psdb-st"> <aside class="psdb-st-sidebar"> <div class="psdb-st-sidebar-title">Functions</div> <div class="psdb-st-sidebar-search"> <input type="text" id="search" placeholder="Search..."> </div> <ul class="psdb-st-sidebar-list" id="function-list"></ul> </aside> <main class="psdb-st-content"> <div class="psdb-st-header"> <h1 class="psdb-st-h1">sqmSQLTool</h1> <p class="psdb-st-subtitle">Command Reference - $($functions.Count) Functions</p> </div> <div class="psdb-st-functions" id="functions-container"></div> </main> </div> <script> const functions = $functionsJson; function renderFunctions(toRender) { const container = document.getElementById('functions-container'); container.innerHTML = ''; toRender.forEach(func => { const card = document.createElement('div'); card.className = 'psdb-st-card'; card.id = 'func-' + func.Name.toLowerCase().replace(/[^a-z0-9-]/g, ''); let paramsHtml = ''; if (func.Params && func.Params.length > 0) { paramsHtml = '<div class="psdb-st-section-title">Parameters</div><ul class="psdb-st-params">'; func.Params.forEach(p => { paramsHtml += '<li class="psdb-st-param">' + escapeHtml(p) + '</li>'; }); paramsHtml += '</ul>'; } let examplesHtml = ''; if (func.Examples && func.Examples.length > 0) { examplesHtml = '<div class="psdb-st-section-title">Examples</div><div class="psdb-st-examples">'; func.Examples.forEach(ex => { examplesHtml += '<div class="psdb-st-example">' + escapeHtml(ex) + '</div>'; }); examplesHtml += '</div>'; } card.innerHTML = ` <div class="psdb-st-card-title">\${escapeHtml(func.Name)}</div> <div class="psdb-st-card-synopsis">\${escapeHtml(func.Synopsis || 'No description available')}</div> \${paramsHtml} \${examplesHtml} `; container.appendChild(card); }); } function filterFunctions() { const query = document.getElementById('search').value.toLowerCase(); const filtered = functions.filter(f => f.Name.toLowerCase().includes(query) || (f.Synopsis && f.Synopsis.toLowerCase().includes(query)) ); document.querySelectorAll('.psdb-st-card').forEach(card => { if (filtered.find(f => 'func-' + f.Name.toLowerCase().replace(/[^a-z0-9-]/g, '') === card.id)) { card.classList.remove('hidden'); } else { card.classList.add('hidden'); } }); updateSidebar(filtered); } function updateSidebar(toShow) { const list = document.getElementById('function-list'); list.innerHTML = ''; toShow.forEach(func => { const item = document.createElement('li'); item.className = 'psdb-st-sidebar-item'; const link = document.createElement('a'); link.className = 'psdb-st-sidebar-link'; link.href = '#func-' + func.Name.toLowerCase().replace(/[^a-z0-9-]/g, ''); link.textContent = func.Name; item.appendChild(link); list.appendChild(item); }); } function escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } // Initialize renderFunctions(functions); updateSidebar(functions); document.getElementById('search').addEventListener('input', filterFunctions); </script> </body> </html> "@ # Write output $html | Out-File $outputFile -Encoding UTF8 -Force $fileSize = (Get-Item $outputFile).Length / 1024 Write-Host "✓ Generated: $outputFile" -ForegroundColor Green Write-Host " Functions: $($functions.Count)" Write-Host " File size: $([Math]::Round($fileSize, 1)) KB" Write-Host " Examples: YES" |