마크다운 표 파싱 로직 분리
This commit is contained in:
112
lib/markdown-table.js
Normal file
112
lib/markdown-table.js
Normal file
@@ -0,0 +1,112 @@
|
||||
/**
|
||||
* 마크다운 표 행 후보인지 확인한다.
|
||||
* @param {string} line - 원본 줄
|
||||
* @returns {boolean} 표 행 후보 여부
|
||||
*/
|
||||
export const isMarkdownTableRow = (line) => {
|
||||
const value = String(line || '').trim()
|
||||
return value.startsWith('|') && value.endsWith('|') && value.split('|').length >= 4
|
||||
}
|
||||
|
||||
/**
|
||||
* 마크다운 표 행을 셀 배열로 나눈다.
|
||||
* @param {string} line - 원본 줄
|
||||
* @returns {string[]} 셀 목록
|
||||
*/
|
||||
export const splitMarkdownTableRow = (line) => {
|
||||
const value = String(line || '').trim().replace(/^\|/, '').replace(/\|$/, '')
|
||||
const cells = []
|
||||
let cell = ''
|
||||
let escaped = false
|
||||
|
||||
for (const character of value) {
|
||||
if (escaped) {
|
||||
cell += character === '|' ? '|' : `\\${character}`
|
||||
escaped = false
|
||||
continue
|
||||
}
|
||||
|
||||
if (character === '\\') {
|
||||
escaped = true
|
||||
continue
|
||||
}
|
||||
|
||||
if (character === '|') {
|
||||
cells.push(cell.trim())
|
||||
cell = ''
|
||||
continue
|
||||
}
|
||||
|
||||
cell += character
|
||||
}
|
||||
|
||||
if (escaped) {
|
||||
cell += '\\'
|
||||
}
|
||||
|
||||
cells.push(cell.trim())
|
||||
|
||||
return cells
|
||||
}
|
||||
|
||||
/**
|
||||
* 마크다운 표 구분선 행인지 확인한다.
|
||||
* @param {string} line - 원본 줄
|
||||
* @returns {boolean} 구분선 여부
|
||||
*/
|
||||
export const isMarkdownTableSeparator = (line) => {
|
||||
if (!isMarkdownTableRow(line)) {
|
||||
return false
|
||||
}
|
||||
|
||||
return splitMarkdownTableRow(line).every((cell) => /^:?-{3,}:?$/.test(cell.trim()))
|
||||
}
|
||||
|
||||
/**
|
||||
* 표 정렬 행에서 셀 정렬 값을 파싱한다.
|
||||
* @param {string} cell - 구분선 셀
|
||||
* @returns {'left'|'center'|'right'} 정렬 값
|
||||
*/
|
||||
export const parseMarkdownTableAlignment = (cell) => {
|
||||
const value = String(cell || '').trim()
|
||||
|
||||
if (value.startsWith(':') && value.endsWith(':')) {
|
||||
return 'center'
|
||||
}
|
||||
|
||||
if (value.endsWith(':')) {
|
||||
return 'right'
|
||||
}
|
||||
|
||||
return 'left'
|
||||
}
|
||||
|
||||
/**
|
||||
* 마크다운 표 블록을 파싱한다.
|
||||
* @param {string[]} lines - 전체 마크다운 줄
|
||||
* @param {number} startIndex - 표 시작 후보 줄
|
||||
* @returns {{headers: string[], alignments: string[], rows: string[][], endLine: number, nextIndex: number}|null} 표 메타
|
||||
*/
|
||||
export const parseMarkdownTableBlock = (lines, startIndex) => {
|
||||
if (!isMarkdownTableRow(lines[startIndex]) || !isMarkdownTableSeparator(lines[startIndex + 1])) {
|
||||
return null
|
||||
}
|
||||
|
||||
const headers = splitMarkdownTableRow(lines[startIndex])
|
||||
const alignments = splitMarkdownTableRow(lines[startIndex + 1]).map(parseMarkdownTableAlignment)
|
||||
const rows = []
|
||||
let index = startIndex + 2
|
||||
|
||||
while (index < lines.length && isMarkdownTableRow(lines[index]) && !isMarkdownTableSeparator(lines[index])) {
|
||||
rows.push(splitMarkdownTableRow(lines[index]))
|
||||
index += 1
|
||||
}
|
||||
|
||||
return {
|
||||
headers,
|
||||
alignments,
|
||||
rows,
|
||||
endLine: index - 1,
|
||||
nextIndex: index
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user