import csv import html import sys # language=css page_css = """ body { margin: 0; padding: 0.5rem; font-family: menlo, consolas, monospace; font-size: 14px; } input { font-size: inherit; font-family: inherit; background-color: transparent; padding: 0.25em 0.5em; } table { border-collapse: collapse; width: 100%; } th, td { border: 1px solid black; padding: 8px; text-align: left; } th { background-color: #f2f2f2; } tr:nth-child(even) { background-color: #fdfdfd; } """ # language=js page_script = """ function sortableTable(table) { const sortStates = new Map(); table.querySelectorAll('th').forEach((header, colIndex) => { header.style.cursor = 'pointer'; header.onclick = () => { const isAsc = !sortStates.get(header); const tbody = table.querySelector('tbody'); const rows = [...tbody.rows]; rows.sort((a, b) => { const [valA, valB] = [a, b].map(row => row.cells[colIndex].textContent.trim()); return /^\d+$/.test(valA) ? (valA - valB) * (isAsc ? 1 : -1) : valA.localeCompare(valB) * (isAsc ? 1 : -1); }); sortStates.set(header, isAsc); tbody.replaceChildren(...rows); // Better than innerHTML = '' }; }); } function debounce(func, delay) { let timeoutId; return function(...args) { clearTimeout(timeoutId); timeoutId = setTimeout(() => { func.apply(this, args); }, delay); }; } function addFilterInput(tableElement) { const filterInput = document.createElement('input'); filterInput.type = 'text'; filterInput.placeholder = "Search..."; tableElement.parentNode.insertBefore(filterInput, tableElement); const debouncedFilter = debounce(filter, 100); filterInput.addEventListener('input', () => { debouncedFilter(); }); function filter() { const filterValue = filterInput.value.trim(); const rows = tableElement.querySelectorAll('tbody tr'); rows.forEach(row => { const rowData = row.textContent.toLowerCase(); if (filterValue.startsWith('/') && filterValue.endsWith('/')) { const regex = new RegExp(filterValue.slice(1, -1), 'ig'); row.style.display = regex.test(rowData) ? '' : 'none'; } else { row.style.display = rowData.includes(filterValue.toLowerCase()) ? '' : 'none'; } }); } } sortableTable(document.querySelector('table')); addFilterInput(document.querySelector('table')); """ def csv_to_html(csv_input: str) -> str: try: lines = csv_input.splitlines() delimiter = "\t" if "\t" in lines[0] else "," reader = csv.reader(lines, delimiter=delimiter) header = next(reader) # Get the header row header_html = f'{"".join(f"{html.escape(col)}" for col in header)}' rows = [ f"{''.join(f'{html.escape(cell)}' for cell in row)}" for row in reader ] rows_html = "\n".join(rows) except csv.Error as e: raise ValueError(f"Error parsing CSV: {e}") except StopIteration: return "

No data found in CSV input.

" rendered = f""" Query Results {header_html} {rows_html}
""" return rendered def main(): try: csv_data = sys.stdin.read() html_output = csv_to_html(csv_data) if html_output: print(html_output) except UnicodeDecodeError as e: raise ValueError( f"Error decoding input: {e}. Ensure your CSV data is encoded correctly (e.g., UTF-8)." ) except Exception as e: raise Exception(f"An unexpected error occurred: {e}") if __name__ == "__main__": main()