feat: box-drawing table to GFM pipe table conversion
This commit is contained in:
@@ -333,22 +333,66 @@ function docsExportPdf() {
|
|||||||
|
|
||||||
/* ── 마크다운 렌더 파이프라인 ──────────────────────────────── */
|
/* ── 마크다운 렌더 파이프라인 ──────────────────────────────── */
|
||||||
|
|
||||||
/// box-drawing 문자(┌─┬┐│├─┼┤└─┴┘) 라인을 fenced code block으로 감싸 고정폭 렌더링 보장
|
/// box-drawing 문자(┌─┬┐│├─┼┤└─┴┘) 라인을 감지하여 표는 GFM pipe table(|---|)로,
|
||||||
|
/// 일반 box line은 ``` fence로 감싸 고정폭 렌더링 보장
|
||||||
function docsWrapBoxDrawing(text) {
|
function docsWrapBoxDrawing(text) {
|
||||||
const BOX_RE = /^[ \t]*[┌┐└┘├┤┬┴┼│─━]/;
|
const BOX_RE = /^[ \t]*[┌┐└┘├┤┬┴┼│─━]/;
|
||||||
const lines = text.split('\n');
|
const lines = text.split('\n');
|
||||||
const out = [];
|
const out = [];
|
||||||
let inBlock = false;
|
let inBlock = false;
|
||||||
|
let buf = [];
|
||||||
for (const line of lines) {
|
for (const line of lines) {
|
||||||
const isBox = BOX_RE.test(line);
|
const isBox = BOX_RE.test(line);
|
||||||
if (isBox && !inBlock) { out.push('```'); inBlock = true; }
|
if (isBox && !inBlock) { inBlock = true; buf = [line]; }
|
||||||
else if (!isBox && inBlock) { out.push('```'); inBlock = false; }
|
else if (isBox && inBlock) { buf.push(line); }
|
||||||
out.push(line);
|
else {
|
||||||
|
if (inBlock) { out.push(docsBoxBlockToGfm(buf)); inBlock = false; buf = []; }
|
||||||
|
out.push(line);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (inBlock) out.push('```');
|
if (inBlock) out.push(docsBoxBlockToGfm(buf));
|
||||||
return out.join('\n');
|
return out.join('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// box-drawing block이 표(┬┴┼ + │)면 GFM pipe table로, 아니면 ``` fence로
|
||||||
|
function docsBoxBlockToGfm(buf) {
|
||||||
|
var joined = buf.join('');
|
||||||
|
if (!/[┬┴┼]/.test(joined) || !/│/.test(joined))
|
||||||
|
return '```\n' + buf.join('\n') + '\n```';
|
||||||
|
|
||||||
|
// ┬/┴/┼ 포함 라인에서 컬럼 경계 위치 추출
|
||||||
|
var pat = null;
|
||||||
|
for (var i = 0; i < buf.length; i++) { if (/[┬┴┼]/.test(buf[i])) { pat = buf[i]; break; } }
|
||||||
|
if (!pat) return '```\n' + buf.join('\n') + '\n```';
|
||||||
|
|
||||||
|
var seps = [];
|
||||||
|
for (var i = 0; i < pat.length; i++) {
|
||||||
|
if ('┬┴┼┌└├┐┘┤'.indexOf(pat[i]) >= 0) seps.push(i);
|
||||||
|
}
|
||||||
|
if (seps.length < 2) return '```\n' + buf.join('\n') + '\n```';
|
||||||
|
|
||||||
|
var numCols = seps.length - 1;
|
||||||
|
var dataRows = [];
|
||||||
|
for (var i = 0; i < buf.length; i++) {
|
||||||
|
if (/^[ \t]*│/.test(buf[i])) dataRows.push(buf[i]);
|
||||||
|
}
|
||||||
|
if (dataRows.length === 0) return '```\n' + buf.join('\n') + '\n```';
|
||||||
|
|
||||||
|
var result = [];
|
||||||
|
// header
|
||||||
|
var hdr = [];
|
||||||
|
for (var c = 0; c < numCols; c++) hdr.push(dataRows[0].substring(seps[c] + 1, seps[c + 1]).trim());
|
||||||
|
result.push('| ' + hdr.join(' | ') + ' |');
|
||||||
|
result.push('|' + ' --- |'.repeat(numCols));
|
||||||
|
// data
|
||||||
|
for (var r = 1; r < dataRows.length; r++) {
|
||||||
|
var row = [];
|
||||||
|
for (var c = 0; c < numCols; c++) row.push(dataRows[r].substring(seps[c] + 1, seps[c + 1]).trim());
|
||||||
|
result.push('| ' + row.join(' | ') + ' |');
|
||||||
|
}
|
||||||
|
return result.join('\n');
|
||||||
|
}
|
||||||
|
|
||||||
function docsRenderMarkdownInto(el, text) {
|
function docsRenderMarkdownInto(el, text) {
|
||||||
text = docsWrapBoxDrawing(text);
|
text = docsWrapBoxDrawing(text);
|
||||||
const rawHtml = marked.parse(text, { gfm: true, breaks: false });
|
const rawHtml = marked.parse(text, { gfm: true, breaks: false });
|
||||||
|
|||||||
Reference in New Issue
Block a user