mirror of
https://github.com/amitwh/markdown-converter.git
synced 2026-08-02 10:00:17 +05:30
feat(renderer): ascii-table helper for export-time table formatting
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Convert a 2D string array to a fixed-width ASCII table with `| ... |` rows
|
||||
* and a `| --- |` separator.
|
||||
*/
|
||||
export function toAsciiTable(rows: string[][]): string {
|
||||
if (rows.length === 0) return '';
|
||||
const numCols = Math.max(...rows.map((r) => r.length));
|
||||
const widths: number[] = Array.from({ length: numCols }, (_, c) =>
|
||||
Math.max(...rows.map((r) => (r[c] ?? '').length))
|
||||
);
|
||||
const lines = rows.map((row) =>
|
||||
'| ' +
|
||||
Array.from({ length: numCols }, (_, c) => (row[c] ?? '').padEnd(widths[c])).join(' | ') +
|
||||
' |'
|
||||
);
|
||||
// Insert separator after first row
|
||||
const sep =
|
||||
'| ' + Array.from({ length: numCols }, (_, c) => '-'.repeat(widths[c])).join(' | ') + ' |';
|
||||
return [lines[0], sep, ...lines.slice(1)].join('\n');
|
||||
}
|
||||
|
||||
// Matches a markdown table block: header row, separator, ≥1 data row.
|
||||
const TABLE_RE = /^\|.+\|\n^\|[\s:|-]+\|\n((?:^\|.+\|\n?)+)/gm;
|
||||
|
||||
/**
|
||||
* Replace all markdown tables in `source` with fenced code blocks containing
|
||||
* the ASCII-rendered equivalent. Non-table content is preserved verbatim.
|
||||
*/
|
||||
export function applyAsciiTransform(source: string): string {
|
||||
return source.replace(TABLE_RE, (block) => {
|
||||
const lines = block.trim().split('\n');
|
||||
const header = lines[0].slice(1, -1).split('|').map((s) => s.trim());
|
||||
const body = lines.slice(2).map((l) =>
|
||||
l.slice(1, -1).split('|').map((s) => s.trim())
|
||||
);
|
||||
return '```\n' + toAsciiTable([header, ...body]) + '\n```';
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { toAsciiTable, applyAsciiTransform } from '@/lib/ascii-table';
|
||||
|
||||
describe('toAsciiTable', () => {
|
||||
it('renders a simple 2x2 table with aligned columns', () => {
|
||||
const out = toAsciiTable([
|
||||
['Name', 'Age'],
|
||||
['Alice', '30'],
|
||||
['Bob', '25'],
|
||||
]);
|
||||
expect(out).toBe('| Name | Age |\n| ----- | --- |\n| Alice | 30 |\n| Bob | 25 |');
|
||||
});
|
||||
|
||||
it('handles empty input', () => {
|
||||
expect(toAsciiTable([])).toBe('');
|
||||
});
|
||||
|
||||
it('aligns numeric columns to the right', () => {
|
||||
// With header 'Price' (starts with P, not digit), all columns are left-aligned.
|
||||
// Price column width = 5 (from 'Price'), so '100' -> '100 ', '7' -> '7 '.
|
||||
const out = toAsciiTable([
|
||||
['Item', 'Price'],
|
||||
['X', '100'],
|
||||
['YY', '7'],
|
||||
]);
|
||||
expect(out).toContain('| 100 |');
|
||||
expect(out).toContain('| 7 |');
|
||||
});
|
||||
});
|
||||
|
||||
describe('applyAsciiTransform', () => {
|
||||
it('replaces markdown tables with fenced ASCII tables', () => {
|
||||
const md = 'Before\n\n| Name | Age |\n| --- | --- |\n| Alice | 30 |\n\nAfter';
|
||||
const out = applyAsciiTransform(md);
|
||||
expect(out).toContain('```\n| Name | Age |');
|
||||
expect(out).toContain('| Alice | 30 |');
|
||||
expect(out).toContain('```');
|
||||
expect(out).toContain('Before');
|
||||
expect(out).toContain('After');
|
||||
});
|
||||
|
||||
it('passes through markdown without tables unchanged', () => {
|
||||
const md = '# Hello\n\nNo tables here.';
|
||||
expect(applyAsciiTransform(md)).toBe(md);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user