From 945b4102f37bcb016fa1e582da0a478f202d0ab1 Mon Sep 17 00:00:00 2001 From: scotttong Date: Fri, 7 Aug 2026 18:06:37 -0700 Subject: [PATCH] fix(markdown): respect fenced block closers --- packages/shared/src/validators/text.test.ts | 5 +++++ packages/shared/src/validators/text.ts | 8 ++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/shared/src/validators/text.test.ts b/packages/shared/src/validators/text.test.ts index 90950765bd8..cda9ca57a12 100644 --- a/packages/shared/src/validators/text.test.ts +++ b/packages/shared/src/validators/text.test.ts @@ -62,6 +62,11 @@ describe("normalizeMidLineHeadings", () => { expect(normalizeMidLineHeadings(body)).toBe(body); }); + it("does not close a fence marker that has trailing content", () => { + const body = "```markdown\n``` still code\ncode ## comment\n```"; + expect(normalizeMidLineHeadings(body)).toBe(body); + }); + it("is a no-op when there is no `#` at all", () => { const body = "Just some prose with no markers."; expect(normalizeMidLineHeadings(body)).toBe(body); diff --git a/packages/shared/src/validators/text.ts b/packages/shared/src/validators/text.ts index 1ecf46704bf..62c1b36eba4 100644 --- a/packages/shared/src/validators/text.ts +++ b/packages/shared/src/validators/text.ts @@ -7,7 +7,7 @@ export function normalizeEscapedLineBreaks(value: string): string { .replace(/\\r/g, "\n"); } -const FENCE_LINE = /^(\s{0,3})(```+|~~~+)/; +const FENCE_LINE = /^(\s{0,3})(```+|~~~+)(.*)$/; // A mid-line ATX heading marker: 1–6 `#`, a space, then heading text. The // capture keeps the char immediately before the run so we can tell a real // (collapsed) heading from an inline `#` token like `C#`/`F#`. @@ -53,7 +53,11 @@ export function normalizeMidLineHeadings(value: string): string { inFence = true; fenceChar = marker[0]!; fenceLength = marker.length; - } else if (marker[0] === fenceChar && marker.length >= fenceLength) { + } else if ( + marker[0] === fenceChar + && marker.length >= fenceLength + && fenceMatch[3]!.trim().length === 0 + ) { inFence = false; fenceChar = ""; fenceLength = 0;