From 0600b3f62a1ecadc0deef105eeb11ab18bdf2aad Mon Sep 17 00:00:00 2001 From: Roo Code Date: Thu, 19 Feb 2026 14:57:54 +0000 Subject: [PATCH] fix: strengthen type guard in countMarkdownHeadings to prevent TypeError on non-string input Fixes #11605. The existing guard `if (!text)` only catches falsy values. When a truthy non-string value (e.g. number or object from an API response) is passed through OpenMarkdownPreviewButton, it passes the guard and text.replace() throws "TypeError: n.replace is not a function". Changed the guard to `typeof text !== "string"` so any non-string value returns 0 early. Added test cases for non-string inputs. --- webview-ui/src/utils/__tests__/markdown.spec.ts | 10 ++++++++++ webview-ui/src/utils/markdown.ts | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/webview-ui/src/utils/__tests__/markdown.spec.ts b/webview-ui/src/utils/__tests__/markdown.spec.ts index 97b3fdaaf2f..7b4dfad7c37 100644 --- a/webview-ui/src/utils/__tests__/markdown.spec.ts +++ b/webview-ui/src/utils/__tests__/markdown.spec.ts @@ -8,6 +8,16 @@ describe("markdown heading helpers", () => { expect(countMarkdownHeadings("")).toBe(0) }) + it("returns 0 for non-string values", () => { + // These simulate runtime scenarios where a non-string truthy value + // is passed due to unexpected API data (see issue #11605) + expect(countMarkdownHeadings(42 as unknown as string)).toBe(0) + expect(countMarkdownHeadings({ key: "value" } as unknown as string)).toBe(0) + expect(countMarkdownHeadings(["# heading"] as unknown as string)).toBe(0) + expect(countMarkdownHeadings(true as unknown as string)).toBe(0) + expect(countMarkdownHeadings(null as unknown as string)).toBe(0) + }) + it("counts single and multiple headings", () => { expect(countMarkdownHeadings("# One")).toBe(1) expect(countMarkdownHeadings("# One\nContent")).toBe(1) diff --git a/webview-ui/src/utils/markdown.ts b/webview-ui/src/utils/markdown.ts index 7a77b9866db..27676f90417 100644 --- a/webview-ui/src/utils/markdown.ts +++ b/webview-ui/src/utils/markdown.ts @@ -4,7 +4,7 @@ * Code fences are stripped before matching to avoid false positives. */ export function countMarkdownHeadings(text: string | undefined): number { - if (!text) return 0 + if (typeof text !== "string" || !text) return 0 // Remove fenced code blocks to avoid counting headings inside code const withoutCodeBlocks = text.replace(/```[\s\S]*?```/g, "")