From 01ca4717767ca01f1bd645ecee0b2bdf780eca5d Mon Sep 17 00:00:00 2001 From: Bohdan Triapitsyn Date: Tue, 14 Apr 2026 19:40:36 +0300 Subject: [PATCH] fix: render JSON code block quotes correctly --- .../src/components/chat/MarkdownRenderer.tsx | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/packages/ui/src/components/chat/MarkdownRenderer.tsx b/packages/ui/src/components/chat/MarkdownRenderer.tsx index 36ba3ab3..419d5541 100644 --- a/packages/ui/src/components/chat/MarkdownRenderer.tsx +++ b/packages/ui/src/components/chat/MarkdownRenderer.tsx @@ -648,6 +648,35 @@ const getCodeLanguage = (className: string | undefined): string => { return match?.[1]?.toLowerCase() ?? 'text'; }; +const decodeHtmlEntities = (value: string): string => { + let decoded = value; + for (let i = 0; i < 3; i += 1) { + const next = decoded + .replace(/"/g, '"') + .replace(/"/g, '"') + .replace(/'/g, "'") + .replace(/'/g, "'") + .replace(/</g, '<') + .replace(/>/g, '>') + .replace(/&/g, '&'); + if (next === decoded) { + return decoded; + } + decoded = next; + } + return decoded; +}; + +const normalizeCodeBlockText = (code: string, language: string): string => { + if (!['json', 'jsonc', 'json5'].includes(language)) { + return code; + } + if (!/&(quot|#34|amp;quot|lt|gt|amp|apos|#39);/.test(code)) { + return code; + } + return decodeHtmlEntities(code); +}; + const MarkdownCodeBlock: React.FC<{ code: string; language: string; @@ -751,8 +780,8 @@ const buildMarkdownComponents = ({ pre({ children, ...props }) { const child = React.Children.only(children) as React.ReactElement<{ className?: string; children?: React.ReactNode }>; const className = child.props.className; - const code = extractCodeText(child.props.children).replace(/\n$/, ''); const language = getCodeLanguage(className); + const code = normalizeCodeBlockText(extractCodeText(child.props.children).replace(/\n$/, ''), language); if (language === 'mermaid') { return ; }