Skip to content

Commit 8e7359d

Browse files
committed
fix: improved parsing of markdown fenced codeblocks' langtag args
1 parent 1adf2dc commit 8e7359d

File tree

2 files changed

+31
-14
lines changed

2 files changed

+31
-14
lines changed

src/components/ChatMessage.tsx

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,22 @@ marked.use(
2828
})
2929
);
3030

31-
export function handleWrappedFencedCodeBlocks(content: string) {
31+
interface ProcessedContent {
32+
processedContent: string;
33+
fences: string[];
34+
}
35+
36+
export function processNestedCodeBlocks(content: string): ProcessedContent {
3237
// Early exit if no code blocks
3338
if (content.split('```').length < 3) {
34-
return content;
39+
return { processedContent: content, fences: [] };
3540
}
3641

3742
const lines = content.split('\n');
3843
const stack: string[] = []; // Stack of language tags to track nesting
3944
let result = '';
4045
let currentBlock: string[] = [];
46+
const fences: string[] = []; // Store all fence info for later use
4147

4248
for (const line of lines) {
4349
const strippedLine = line.trim();
@@ -48,6 +54,7 @@ export function handleWrappedFencedCodeBlocks(content: string) {
4854
const remainingContent = lines.slice(lines.indexOf(line) + 1).join('\n');
4955
if (remainingContent.includes('```') && remainingContent.split('```').length > 2) {
5056
stack.push(lang);
57+
fences.push(lang); // Store fence info
5158
result += '~~~' + lang + '\n';
5259
} else {
5360
result += line + '\n';
@@ -77,7 +84,10 @@ export function handleWrappedFencedCodeBlocks(content: string) {
7784
}
7885
}
7986

80-
return result.trim();
87+
return {
88+
processedContent: result.trim(),
89+
fences
90+
};
8191
}
8292

8393
export function transformThinkingTags(content: string) {
@@ -103,15 +113,13 @@ export const ChatMessage: FC<Props> = ({ message }) => {
103113
const processContent = async () => {
104114
try {
105115
// Transform thinking tags before markdown parsing
106-
let processedContent = transformThinkingTags(content);
116+
const processedContent = transformThinkingTags(content);
107117

108118
// Handle wrapped fenced code blocks
109-
processedContent = handleWrappedFencedCodeBlocks(processedContent);
110-
111-
// Find start fences for codeblocks (hljs doesn't include paths like "```save PATH")
112-
const fences = [...processedContent.matchAll(/(~~~|```)[^\n]+/g)].map((s: RegExpExecArray) => s[0].replace(/(~~~|```)/g, ""));
119+
// Process nested code blocks and collect fence info
120+
const { processedContent: transformedContent, fences } = processNestedCodeBlocks(processedContent);
113121

114-
let parsedResult = await marked.parse(processedContent, {
122+
let parsedResult = await marked.parse(transformedContent, {
115123
async: true,
116124
});
117125

src/components/__tests__/ChatMessage.test.tsx

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { handleWrappedFencedCodeBlocks, transformThinkingTags } from '../ChatMessage';
1+
import { processNestedCodeBlocks, transformThinkingTags } from '../ChatMessage';
22

3-
describe('handleWrappedFencedCodeBlocks', () => {
3+
describe('processNestedCodeBlocks', () => {
44
it('should handle nested code blocks', () => {
55
const input = `\`\`\`markdown
66
Here's a nested block
@@ -16,15 +16,21 @@ print("hello")
1616
\`\`\`
1717
~~~`;
1818

19-
expect(handleWrappedFencedCodeBlocks(input)).toBe(expected);
19+
expect(processNestedCodeBlocks(input)).toEqual({
20+
processedContent: expected,
21+
fences: ['markdown']
22+
});
2023
});
2124

2225
it('should not modify single code blocks', () => {
2326
const input = `\`\`\`python
2427
print("hello")
2528
\`\`\``;
2629

27-
expect(handleWrappedFencedCodeBlocks(input)).toBe(input);
30+
expect(processNestedCodeBlocks(input)).toEqual({
31+
processedContent: input,
32+
fences: []
33+
});
2834
});
2935

3036
it('should handle multiple nested blocks', () => {
@@ -50,7 +56,10 @@ console.log("world")
5056
\`\`\`
5157
~~~`;
5258

53-
expect(handleWrappedFencedCodeBlocks(input)).toBe(expected);
59+
expect(processNestedCodeBlocks(input)).toEqual({
60+
processedContent: expected,
61+
fences: ['markdown']
62+
});
5463
});
5564
});
5665

0 commit comments

Comments
 (0)