Skip to content
This repository was archived by the owner on Mar 18, 2026. It is now read-only.

Commit fc4a24e

Browse files
authored
Merge pull request #280 from X2bee/main
feat: Enhance Markdown processing by normalizing non-standard pipe ch…
2 parents f206e6f + 27a9e26 commit fc4a24e

File tree

2 files changed

+27
-13
lines changed

2 files changed

+27
-13
lines changed

src/app/_common/components/chatParser/ChatParser.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ import {
2525
findTodoDetailsBlocks
2626
} from '@/app/_common/components/chatParser/ChatParserTodoDetails';
2727
import {
28-
parseSimpleMarkdown
28+
parseSimpleMarkdown,
29+
normalizeTableSeparators
2930
} from '@/app/_common/components/chatParser/ChatParserMarkdown';
3031
import { parseCitation } from '@/app/_common/components/chatParser/ChatParserCite';
3132
import { convertToString, needsConversion } from '@/app/_common/components/chatParser/ChatParserNonStr';
@@ -50,7 +51,7 @@ interface MessageRendererProps {
5051
className?: string;
5152
onViewSource?: (sourceInfo: SourceInfo) => void;
5253
onHeightChange?: () => void;
53-
mode?: "existing" | "new-workflow" | "new-default" | "deploy";
54+
mode?: "existing" | "new-workflow" | "new-default" | "deploy" | "embed";
5455
messageId?: string; // 메시지 고유 식별자 추가
5556
timestamp?: number; // 메시지 생성 시간 추가
5657
showEditButton?: boolean; // 편집 버튼 표시 여부
@@ -140,13 +141,14 @@ export const MessageRenderer: React.FC<MessageRendererProps> = ({
140141
/**
141142
* 컨텐츠를 React 엘리먼트로 파싱
142143
*/
143-
const parseContentToReactElements = (content: string, onViewSource?: (sourceInfo: SourceInfo) => void, onHeightChange?: () => void, mode?: "existing" | "new-workflow" | "new-default" | "deploy"): React.ReactNode[] => {
144+
const parseContentToReactElements = (content: string, onViewSource?: (sourceInfo: SourceInfo) => void, onHeightChange?: () => void, mode?: "existing" | "new-workflow" | "new-default" | "deploy" | "embed"): React.ReactNode[] => {
144145
// 이 시점에서 content는 이미 MessageRenderer에서 문자열로 변환되었음
145146
if (!content) {
146147
return [];
147148
}
148149

149-
let processed = content;
150+
// 비표준 파이프 문자를 먼저 정규화
151+
let processed = normalizeTableSeparators(content);
150152

151153
// 스트림 모드 감지를 위한 헬퍼 함수
152154
const detectStreaming = (text: string, textStartIndex: number, totalLength: number): boolean => {

src/app/_common/components/chatParser/ChatParserMarkdown.tsx

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,18 @@ import { processInlineMarkdownWithCitations } from '@/app/_common/components/cha
1111
*/
1212
export const normalizeTableSeparators = (text: string): string => {
1313
return text
14+
.replace(//g, '|') // ∣ (U+2223 DIVIDES) → |
1415
.replace(/\u2223/g, '|') // ∣ (DIVIDES) → |
1516
.replace(/\u2502/g, '|') // │ (BOX DRAWINGS LIGHT VERTICAL) → |
16-
.replace(/\uFF5C/g, '|'); // | (FULLWIDTH VERTICAL LINE) → |
17+
.replace(/\uFF5C/g, '|') // | (FULLWIDTH VERTICAL LINE) → |
18+
.replace(//g, '|') // | (FULLWIDTH VERTICAL LINE) → |
19+
.replace(//g, '|') // │ (BOX DRAWINGS) → |
20+
.replace(/\u007C/g, '|') // | (VERTICAL LINE, 정규화) → |
21+
.replace(/\u01C0/g, '|') // ǀ (LATIN LETTER DENTAL CLICK) → |
22+
.replace(/\u05C0/g, '|') // ׀ (HEBREW PUNCTUATION PASEQ) → |
23+
.replace(/\u2758/g, '|') // ❘ (LIGHT VERTICAL BAR) → |
24+
.replace(/\u2759/g, '|') // ❙ (MEDIUM VERTICAL BAR) → |
25+
.replace(/\u275A/g, '|'); // ❚ (HEAVY VERTICAL BAR) → |
1726
};
1827

1928
/**
@@ -319,13 +328,16 @@ export const parseSimpleMarkdown = (
319328
): React.ReactNode[] => {
320329
if (!text.trim()) return [];
321330

331+
// 비표준 파이프 문자를 먼저 정규화
332+
const normalizedText = normalizeTableSeparators(text);
333+
322334
// LaTeX가 포함된 경우 전체 텍스트를 LaTeX 처리기로 넘김 (라인 분할하지 않음)
323-
if (hasLatex(text)) {
324-
return processLatexInText(text, `${startKey}-latex`, isStreaming, onHeightChange);
335+
if (hasLatex(normalizedText)) {
336+
return processLatexInText(normalizedText, `${startKey}-latex`, isStreaming, onHeightChange);
325337
}
326338

327339
const elements: React.ReactNode[] = [];
328-
const lines = text.split('\n');
340+
const lines = normalizedText.split('\n');
329341

330342
// 연속된 빈 줄을 하나로 축소하여 처리
331343
const processedLines: string[] = [];
@@ -344,24 +356,24 @@ export const parseSimpleMarkdown = (
344356
}
345357

346358
for (let i = 0; i < processedLines.length; i++) {
347-
const line = normalizeTableSeparators(processedLines[i]);
359+
const line = processedLines[i];
348360
const key = `${startKey}-block-${i}`;
349361

350362
// --- 테이블 파싱 로직 (추가된 부분) ---
351363
const isTableLine = (str: string) => str.trim().includes('|');
352364
const isTableSeparator = (str: string) => /^\s*\|?(\s*:?-+:?\s*\|)+(\s*:?-+:?\s*\|?)\s*$/.test(str.trim());
353365

354-
const nextLine = processedLines[i + 1] ? normalizeTableSeparators(processedLines[i + 1]) : undefined;
366+
const nextLine = processedLines[i + 1] ? processedLines[i + 1] : undefined;
355367
if (isTableLine(line) && nextLine && isTableSeparator(nextLine)) {
356368
const headerLine = line;
357369
const separatorLine = nextLine;
358370
const bodyLines = [];
359371

360372
let tableEndIndex = i + 2;
361373
while (tableEndIndex < processedLines.length) {
362-
const normalizedLine = normalizeTableSeparators(processedLines[tableEndIndex]);
363-
if (isTableLine(normalizedLine) && !isTableSeparator(normalizedLine)) {
364-
bodyLines.push(normalizedLine);
374+
const currentLine = processedLines[tableEndIndex];
375+
if (isTableLine(currentLine) && !isTableSeparator(currentLine)) {
376+
bodyLines.push(currentLine);
365377
tableEndIndex++;
366378
} else {
367379
break;

0 commit comments

Comments
 (0)