From 444e47c3c0866a614052a7ba6ff10421bfd088bc Mon Sep 17 00:00:00 2001 From: youdie006 Date: Wed, 19 Aug 2026 14:14:34 +0900 Subject: [PATCH] Close fenced div on CRLF input With CRLF line endings, a fenced div's closing ::: fence is not detected, so the div never closes and all following content is swallowed inside it. In the fenced_div continue callback (src/block.ts), the parser sets this.pos = m.endpos; the fence pattern (::::*)[ \t]*\r?\n matches through the \n, so on CRLF input m.endpos lands on the \n, one past the \r that getEol() records as starteol. The main loop then evaluates isBlank = (pos === starteol) as false, mistakes the fence line for a lazy paragraph continuation, and never closes the div. On LF the two positions coincide so it works by coincidence. Set this.pos = this.starteol, the position just before the line ending, correct for both LF and CRLF, mirroring the sibling code_block close path. LF output is byte-identical. Fixes #113. --- src/block.ts | 2 +- src/html.spec.ts | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/block.ts b/src/block.ts index 7df45e4..7ffb864 100644 --- a/src/block.ts +++ b/src/block.ts @@ -642,7 +642,7 @@ class EventParser { if (colons.length >= container.extra.colons) { container.extra.endFenceStartpos = m.startpos; container.extra.endFenceEndpos = m.startpos + colons.length - 1; - this.pos = m.endpos; // before newline + this.pos = this.starteol; // before newline (CRLF-safe, see #113) return false; } } diff --git a/src/html.spec.ts b/src/html.spec.ts index 2ea00ba..e83a775 100644 --- a/src/html.spec.ts +++ b/src/html.spec.ts @@ -36,4 +36,19 @@ rendering the light markup format djot.

); }); + it("closes a fenced div with CRLF line endings", () => { + // Regression test for issue #113: with CRLF line endings the closing + // ::: fence must close the div, so following content ("after") lands + // outside the div rather than being swallowed inside an unclosed div. + const expected = +`
+

hello

+
+

after

+`; + expect(renderHTML(parse(":::\r\nhello\r\n:::\r\nafter\r\n"))).toEqual(expected); + // The LF equivalent is unchanged and produces byte-identical HTML. + expect(renderHTML(parse(":::\nhello\n:::\nafter\n"))).toEqual(expected); + }); + });