Fix regex for code block end detection in wikiparser (#9739)

* Fix regex for code block end detection in wikiparser

* Anchor the codeblock end fence to its own line

Close an empty code block without consuming the tiddler, while a fence
only counts when it stands alone on its line.

* Match the end fence with (^|\r?\n) so the empty block case closes at
  the line start and a code line ending in ``` stays inside the block
* Add test-codeblock-parser.js covering empty blocks with language and
  CRLF, delimiter newline handling, mid-line fences and a missing fence
This commit is contained in:
Mario Pietsch authored and GitHub committed 2026-07-22 13:12:55 +02:00
1 parent 855dc2fbb9
commit 97e27d0dad
3 files changed
+83 -1

No files matched your search

@@ -25,7 +25,7 @@ exports.init = function(parser) {
};
exports.parse = function() {
var reEnd = /(\r?\n```$)/mg;
var reEnd = /(^|\r?\n)```$/mg;
var languageStart = this.parser.pos + 3,
languageEnd = languageStart + this.match[1].length;
// Move past the match
@@ -0,0 +1,69 @@
/*\
title: test-codeblock-parser.js
type: application/javascript
tags: [[$:/tags/test-spec]]
Tests the codeblock wikitext rule (#9047): an empty code block must parse
cleanly, and a closing fence only counts when it stands alone on its line.
\*/
"use strict";
describe("codeblock parser tests (#9047)", function() {
var wiki = new $tw.Wiki();
function parse(text) {
return wiki.parseText("text/vnd.tiddlywiki",text).tree;
}
it("parses an empty code block with a language", function() {
// Browser console: $tw.wiki.parseText("text/vnd.tiddlywiki","```bash\n```").tree
// Expected: one codeblock node, code "", language "bash".
var tree = parse("```bash\n```");
expect(tree.length).toBe(1);
expect(tree[0].type).toBe("codeblock");
expect(tree[0].attributes.code.value).toBe("");
expect(tree[0].attributes.language.value).toBe("bash");
});
it("handles CRLF line endings around both fences", function() {
// Browser console: $tw.wiki.parseText("text/vnd.tiddlywiki","```bash\r\nfoo\r\n```").tree
// Expected: one codeblock node with code "foo"; neither the CRLF after the
// opening fence nor the one before the closing fence is part of the code.
var tree = parse("```bash\r\nfoo\r\n```");
expect(tree.length).toBe(1);
expect(tree[0].type).toBe("codeblock");
expect(tree[0].attributes.code.value).toBe("foo");
});
it("keeps the content of a block and drops the delimiting newlines", function() {
// Browser console: $tw.wiki.parseText("text/vnd.tiddlywiki","```\nfoo\n```").tree
// Expected: one codeblock node with code "foo"; the newlines around the
// delimiter lines are not part of the code.
var tree = parse("```\nfoo\n```");
expect(tree.length).toBe(1);
expect(tree[0].type).toBe("codeblock");
expect(tree[0].attributes.code.value).toBe("foo");
});
it("only closes the block when the fence stands alone on its line", function() {
// A content line ending in ``` is code, not a closing fence, e.g. nested
// markdown fences or template literals quoted inside a code block.
// Browser console: $tw.wiki.parseText("text/vnd.tiddlywiki","```\nabc```\ndef\n```").tree
// Expected: one codeblock containing "abc```\ndef"; nothing leaks out as wikitext.
var tree = parse("```\nabc```\ndef\n```");
expect(tree.length).toBe(1);
expect(tree[0].type).toBe("codeblock");
expect(tree[0].attributes.code.value).toBe("abc```\ndef");
});
it("swallows the rest of the tiddler when no closing fence exists", function() {
// Browser console: $tw.wiki.parseText("text/vnd.tiddlywiki","```bash\nfoo").tree
// Expected: one codeblock node with code "foo", extending to the end of the text.
var tree = parse("```bash\nfoo");
expect(tree.length).toBe(1);
expect(tree[0].type).toBe("codeblock");
expect(tree[0].attributes.code.value).toBe("foo");
});
});
@@ -0,0 +1,13 @@
change-category: hackability
change-type: bugfix
created: 20260711181412000
description: Empty code blocks parse cleanly; a closing fence only counts alone on its line
github-contributors: pmario
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9739
release: 5.5.0
tags: $:/tags/ChangeNote
title: $:/changenotes/5.5.0/#9739
type: text/vnd.tiddlywiki
* An empty code block such as ```` ```bash ```` directly followed by the closing fence parses as an empty codeblock instead of swallowing the rest of the tiddler (fixes [[Issue #9047|https://github.com/TiddlyWiki/TiddlyWiki5/issues/9047]])
* A closing fence only ends the block when it stands alone on its line, so code lines ending in three backticks stay inside the block