From 5e07811952f6f3f74da2eb761a60e235f8ed92c6 Mon Sep 17 00:00:00 2001 From: Nalla Prakash <81852531+prakashNalla@users.noreply.github.com> Date: Mon, 2 Nov 2026 17:31:05 +0530 Subject: [PATCH] fix(widget): drop the whole language tag from a code block --- .changeset/fence-language-tag.md | 5 +++++ packages/widget/src/markdown.ts | 2 +- packages/widget/tests/markdown.test.ts | 17 +++++++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 .changeset/fence-language-tag.md diff --git a/.changeset/fence-language-tag.md b/.changeset/fence-language-tag.md new file mode 100644 index 00000000..59261cde --- /dev/null +++ b/.changeset/fence-language-tag.md @@ -0,0 +1,5 @@ +--- +"@chatcops/widget": patch +--- + +A code block tagged `c++`, `c#` or `objective-c` no longer shows part of the tag as its first line, and a one-line code block keeps all of its text. diff --git a/packages/widget/src/markdown.ts b/packages/widget/src/markdown.ts index 71586fd4..18dfb0f9 100644 --- a/packages/widget/src/markdown.ts +++ b/packages/widget/src/markdown.ts @@ -42,7 +42,7 @@ export function renderMarkdown(input: string): string { // Code blocks (``` ... ```) — stashed before any markdown transformation so // their content stays literal and their newlines survive the
step. - html = html.replace(/```(?:\w*)\n?([\s\S]*?)```/g, (_match, code: string) => { + html = html.replace(/```(?:[^`\n]*\n)?([\s\S]*?)```/g, (_match, code: string) => { return stashHtml(`
${code.trim()}
`); }); diff --git a/packages/widget/tests/markdown.test.ts b/packages/widget/tests/markdown.test.ts index 6ef853b1..28136119 100644 --- a/packages/widget/tests/markdown.test.ts +++ b/packages/widget/tests/markdown.test.ts @@ -21,6 +21,23 @@ describe('renderMarkdown', () => { expect(result).toContain('const x = 1;'); }); + it.each(['c++', 'c#', 'objective-c', 'ts'])('drops a %s language tag from a code block', (lang) => { + expect(renderMarkdown(`\`\`\`${lang}\nint x;\n\`\`\``)).toBe('
int x;
'); + }); + + it('keeps all the text of a one-line code block', () => { + expect(renderMarkdown('```const x```')).toBe('
const x
'); + }); + + it('drops a language tag with a space after it', () => { + expect(renderMarkdown('```ts \nconst x = 1;\n```')).toBe('
const x = 1;
'); + }); + + it('leaves a code block that is still streaming as text', () => { + expect(renderMarkdown('```ts\nconst x = 1;')).toBe('```ts
const x = 1;'); + expect(renderMarkdown('```c++\nint x;')).toBe('```c++
int x;'); + }); + it('renders links', () => { const result = renderMarkdown('[Click here](https://example.com)'); expect(result).toContain('