This commit is contained in:
Zef Hemel
2026-03-21 14:19:11 +01:00
parent 4c5fc1d4de
commit 495bd8e3e6
2 changed files with 73 additions and 1 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
export const wikiLinkRegex =
/(?<leadingTrivia>!?\[\[)(?<stringRef>.*?)(?:\|(?<alias>.*?))?(?<trailingTrivia>\]\])/g;
export const mdLinkRegex = /!?\[(?<title>[^\]]*)\]\((?<url>.+)\)/g;
export const mdLinkRegex = /!?\[(?<title>(?:[^\\\]]+|\\.)*)\]\((?<url>.+)\)/g;
export const tagRegex =
/#(?:(?:\d*[^\d\s!@#$%^&*(),.?":{}|<>\\][^\s!@#$%^&*(),.?":{}|<>\\]*)|(?:<[^>\n]+>))/;
export const nakedUrlRegex =
+72
View File
@@ -7,6 +7,7 @@ import {
import { parseMarkdown } from "./parser.ts";
import { extractHashtag } from "../../plug-api/lib/tags.ts";
import { renderHashtag } from "../../plugs/index/tags.ts";
import { mdLinkRegex } from "./constants.ts";
const sample1 = `---
type: page
@@ -309,3 +310,74 @@ test("Test table parser does not treat {[...]} specially", () => {
const row1Cells = collectNodesOfType(rows[0], "TableCell");
expect(row1Cells.length).toBe(2);
});
// Links with escaped square brackets
test("Test markdown links with escaped square brackets", () => {
// Parser should produce a Link node for escaped brackets
const tree = parseMarkdown(`[\\[link\\]](address)`);
const links = collectNodesOfType(tree, "Link");
expect(links.length).toBe(1);
// Should contain Escape nodes for the brackets
const escapes = collectNodesOfType(links[0], "Escape");
expect(escapes.length).toBe(2);
expect(escapes[0].children![0].text).toBe("\\[");
expect(escapes[1].children![0].text).toBe("\\]");
// Should have a URL node
const urlNode = findNodeOfType(links[0], "URL");
expect(urlNode).not.toBeUndefined();
expect(urlNode!.children![0].text).toBe("address");
// Full roundtrip
expect(renderToText(tree)).toBe(`[\\[link\\]](address)`);
});
test("Test mdLinkRegex with escaped square brackets", () => {
// Normal link
mdLinkRegex.lastIndex = 0;
let match = mdLinkRegex.exec("[link](address)");
expect(match).not.toBeNull();
expect(match!.groups!.title).toBe("link");
expect(match!.groups!.url).toBe("address");
// Escaped brackets in link text (issue #1896)
mdLinkRegex.lastIndex = 0;
match = mdLinkRegex.exec("[\\[link\\]](address)");
expect(match).not.toBeNull();
expect(match!.groups!.title).toBe("\\[link\\]");
expect(match!.groups!.url).toBe("address");
// Escaped brackets with other text
mdLinkRegex.lastIndex = 0;
match = mdLinkRegex.exec("[see \\[ref\\] here](http://example.com)");
expect(match).not.toBeNull();
expect(match!.groups!.title).toBe("see \\[ref\\] here");
expect(match!.groups!.url).toBe("http://example.com");
// Image with escaped brackets
mdLinkRegex.lastIndex = 0;
match = mdLinkRegex.exec("![\\[img\\]](image.png)");
expect(match).not.toBeNull();
expect(match!.groups!.title).toBe("\\[img\\]");
expect(match!.groups!.url).toBe("image.png");
// Other escaped characters (backslash itself)
mdLinkRegex.lastIndex = 0;
match = mdLinkRegex.exec("[a\\\\b](url)");
expect(match).not.toBeNull();
expect(match!.groups!.title).toBe("a\\\\b");
expect(match!.groups!.url).toBe("url");
// Normal link still works (no regressions)
mdLinkRegex.lastIndex = 0;
match = mdLinkRegex.exec("[simple text](http://example.com)");
expect(match).not.toBeNull();
expect(match!.groups!.title).toBe("simple text");
// Empty title still works
mdLinkRegex.lastIndex = 0;
match = mdLinkRegex.exec("[](url)");
expect(match).not.toBeNull();
expect(match!.groups!.title).toBe("");
});