diff --git a/src/telegram/format.ts b/src/telegram/format.ts
index a9ca7bdc6fa..2972acb9845 100644
--- a/src/telegram/format.ts
+++ b/src/telegram/format.ts
@@ -222,11 +222,17 @@ export function wrapFileReferencesInHtml(html: string): string {
`([^a-zA-Z0-9]|^)([A-Za-z]\\.(?:${extensionsPattern}))(?=[^a-zA-Z0-9/]|$)`,
"g",
);
- result = result.replace(orphanedTldPattern, (m, prefix, tld) => {
- // Skip if already wrapped in a tag (check for < before or > after in context)
+ result = result.replace(orphanedTldPattern, (m, prefix, tld, offset) => {
+ // Skip if prefix is > (right after a tag close)
if (prefix === ">") {
return m;
}
+ // Skip if we're inside an HTML tag (between < and >)
+ const lastOpen = result.lastIndexOf("<", offset);
+ const lastClose = result.lastIndexOf(">", offset);
+ if (lastOpen > lastClose) {
+ return m; // Inside a tag
+ }
return `${prefix}${escapeHtml(tld)}`;
});
@@ -239,8 +245,8 @@ export function renderTelegramHtmlText(
): string {
const textMode = options.textMode ?? "markdown";
if (textMode === "html") {
- // For HTML mode, still wrap file references in the HTML
- return wrapFileReferencesInHtml(text);
+ // For HTML mode, trust caller markup - don't modify
+ return text;
}
// markdownToTelegramHtml already wraps file references by default
return markdownToTelegramHtml(text, { tableMode: options.tableMode });
diff --git a/src/telegram/format.wrap-md.test.ts b/src/telegram/format.wrap-md.test.ts
index 5668b3d9661..413b91c1576 100644
--- a/src/telegram/format.wrap-md.test.ts
+++ b/src/telegram/format.wrap-md.test.ts
@@ -101,9 +101,11 @@ describe("renderTelegramHtmlText - file reference wrapping", () => {
expect(result).toContain("README.md");
});
- it("wraps file references in HTML mode", () => {
+ it("does not wrap in HTML mode (trusts caller markup)", () => {
+ // textMode: "html" should pass through unchanged - caller owns the markup
const result = renderTelegramHtmlText("Check README.md", { textMode: "html" });
- expect(result).toContain("README.md");
+ expect(result).toBe("Check README.md");
+ expect(result).not.toContain("");
});
it("does not double-wrap already code-formatted content", () => {
@@ -324,4 +326,19 @@ describe("edge cases", () => {
// Only x.md gets wrapped, the rest passes through
expect(result).toBe("x.mdbold");
});
+
+ it("does not wrap orphaned TLD inside href attributes", () => {
+ // D.md inside href should NOT be wrapped
+ const input = 'link';
+ const result = wrapFileReferencesInHtml(input);
+ // href should be untouched
+ expect(result).toBe(input);
+ expect(result).not.toContain("D.md");
+ });
+
+ it("does not wrap orphaned TLD inside any HTML attribute", () => {
+ const input = '
';
+ const result = wrapFileReferencesInHtml(input);
+ expect(result).toBe(input);
+ });
});