From 2aa979078952f07386c8a271cf299b3244965dce Mon Sep 17 00:00:00 2001 From: shixy <18705837259@163.com> Date: Sat, 14 Mar 2026 17:12:03 +0800 Subject: [PATCH] fix: preserve inline code in cjk emphasis --- packages/baoyu-md/src/renderer.test.ts | 64 +++++++++++++++++++ packages/baoyu-md/src/renderer.ts | 8 +++ .../vendor/baoyu-md/src/renderer.test.ts | 28 ++++++++ .../scripts/vendor/baoyu-md/src/renderer.ts | 9 ++- .../vendor/baoyu-md/src/renderer.test.ts | 64 +++++++++++++++++++ .../scripts/vendor/baoyu-md/src/renderer.ts | 8 +++ .../vendor/baoyu-md/src/renderer.test.ts | 64 +++++++++++++++++++ .../scripts/vendor/baoyu-md/src/renderer.ts | 8 +++ 8 files changed, 252 insertions(+), 1 deletion(-) create mode 100644 packages/baoyu-md/src/renderer.test.ts create mode 100644 skills/baoyu-post-to-wechat/scripts/vendor/baoyu-md/src/renderer.test.ts create mode 100644 skills/baoyu-post-to-weibo/scripts/vendor/baoyu-md/src/renderer.test.ts diff --git a/packages/baoyu-md/src/renderer.test.ts b/packages/baoyu-md/src/renderer.test.ts new file mode 100644 index 0000000..702804c --- /dev/null +++ b/packages/baoyu-md/src/renderer.test.ts @@ -0,0 +1,64 @@ +import assert from "node:assert/strict"; +import test from "node:test"; + +import { initRenderer, renderMarkdown } from "./renderer.ts"; + +const render = (md: string) => { + const r = initRenderer(); + return renderMarkdown(md, r).html; +}; + +test("bold with inline code (no underscore)", () => { + const html = render("**算出 `logits`,算出 `loss`。**"); + assert.match(html, /]*>logits<\/code>/); + assert.match(html, /]*>loss<\/code>/); +}); + +test("bold with inline code (contains underscore)", () => { + const html = render("**变成 `input_ids`。**"); + assert.match(html, /]*>input_ids<\/code>/); +}); + +test("emphasis with inline code", () => { + const html = render("*查看 `hidden_states`*"); + assert.match(html, /]*>hidden_states<\/code>/); +}); + +test("plain inline code (regression)", () => { + const html = render("`lm_head`"); + assert.match(html, /]*>lm_head<\/code>/); +}); + +test("bold without code (regression)", () => { + const html = render("**纯粗体文本**"); + assert.match(html, /]*>纯粗体文本<\/strong>/); + assert.doesNotMatch(html, / { + const html = render("**``a`b``**"); + assert.match(html, /]*>a`b<\/code>/); +}); + +test("emphasis with inline code containing backticks", () => { + const html = render("*``a`b``*"); + assert.match(html, /]*>]*>a`b<\/code><\/em>/); +}); + +test("bold with inline code containing consecutive backticks", () => { + const html = render("**```a``b```**"); + assert.match(html, /]*>a``b<\/code>/); +}); + +test("bold with inline code containing only backticks", () => { + const html = render("**```` `` ````**"); + assert.match(html, /]*>``<\/code>/); +}); + +test("bold with inline code containing only spaces", () => { + const oneSpace = render("**`` ``**"); + assert.match(oneSpace, /]*> <\/code>/); + + const twoSpaces = render("**`` ``**"); + assert.match(twoSpaces, /]*> <\/code>/); +}); diff --git a/packages/baoyu-md/src/renderer.ts b/packages/baoyu-md/src/renderer.ts index 7a1234c..2549737 100644 --- a/packages/baoyu-md/src/renderer.ts +++ b/packages/baoyu-md/src/renderer.ts @@ -109,6 +109,13 @@ function parseFrontMatterAndContent(markdownText: string): ParseResult { } } +function wrapInlineCode(value: string): string { + const runs = value.match(/`+/g); + const fence = "`".repeat(Math.max(...(runs?.map((run) => run.length) ?? [0])) + 1); + const padding = /^ *$/.test(value) ? "" : " "; + return `${fence}${padding}${value}${padding}${fence}`; +} + export function initRenderer(opts: IOpts = {}): RendererAPI { const footnotes: [number, string, string][] = []; let footnoteIndex = 0; @@ -369,6 +376,7 @@ function preprocessCjkEmphasis(markdown: string): string { const tree = processor.parse(markdown); const extractText = (node: any): string => { if (node.type === "text") return node.value; + if (node.type === "inlineCode") return wrapInlineCode(node.value); if (node.children) return node.children.map(extractText).join(""); return ""; }; diff --git a/skills/baoyu-markdown-to-html/scripts/vendor/baoyu-md/src/renderer.test.ts b/skills/baoyu-markdown-to-html/scripts/vendor/baoyu-md/src/renderer.test.ts index 57e7a08..702804c 100644 --- a/skills/baoyu-markdown-to-html/scripts/vendor/baoyu-md/src/renderer.test.ts +++ b/skills/baoyu-markdown-to-html/scripts/vendor/baoyu-md/src/renderer.test.ts @@ -34,3 +34,31 @@ test("bold without code (regression)", () => { assert.match(html, /]*>纯粗体文本<\/strong>/); assert.doesNotMatch(html, / { + const html = render("**``a`b``**"); + assert.match(html, /]*>a`b<\/code>/); +}); + +test("emphasis with inline code containing backticks", () => { + const html = render("*``a`b``*"); + assert.match(html, /]*>]*>a`b<\/code><\/em>/); +}); + +test("bold with inline code containing consecutive backticks", () => { + const html = render("**```a``b```**"); + assert.match(html, /]*>a``b<\/code>/); +}); + +test("bold with inline code containing only backticks", () => { + const html = render("**```` `` ````**"); + assert.match(html, /]*>``<\/code>/); +}); + +test("bold with inline code containing only spaces", () => { + const oneSpace = render("**`` ``**"); + assert.match(oneSpace, /]*> <\/code>/); + + const twoSpaces = render("**`` ``**"); + assert.match(twoSpaces, /]*> <\/code>/); +}); diff --git a/skills/baoyu-markdown-to-html/scripts/vendor/baoyu-md/src/renderer.ts b/skills/baoyu-markdown-to-html/scripts/vendor/baoyu-md/src/renderer.ts index 692f216..2549737 100644 --- a/skills/baoyu-markdown-to-html/scripts/vendor/baoyu-md/src/renderer.ts +++ b/skills/baoyu-markdown-to-html/scripts/vendor/baoyu-md/src/renderer.ts @@ -109,6 +109,13 @@ function parseFrontMatterAndContent(markdownText: string): ParseResult { } } +function wrapInlineCode(value: string): string { + const runs = value.match(/`+/g); + const fence = "`".repeat(Math.max(...(runs?.map((run) => run.length) ?? [0])) + 1); + const padding = /^ *$/.test(value) ? "" : " "; + return `${fence}${padding}${value}${padding}${fence}`; +} + export function initRenderer(opts: IOpts = {}): RendererAPI { const footnotes: [number, string, string][] = []; let footnoteIndex = 0; @@ -369,7 +376,7 @@ function preprocessCjkEmphasis(markdown: string): string { const tree = processor.parse(markdown); const extractText = (node: any): string => { if (node.type === "text") return node.value; - if (node.type === "inlineCode") return `\`${node.value}\``; + if (node.type === "inlineCode") return wrapInlineCode(node.value); if (node.children) return node.children.map(extractText).join(""); return ""; }; diff --git a/skills/baoyu-post-to-wechat/scripts/vendor/baoyu-md/src/renderer.test.ts b/skills/baoyu-post-to-wechat/scripts/vendor/baoyu-md/src/renderer.test.ts new file mode 100644 index 0000000..702804c --- /dev/null +++ b/skills/baoyu-post-to-wechat/scripts/vendor/baoyu-md/src/renderer.test.ts @@ -0,0 +1,64 @@ +import assert from "node:assert/strict"; +import test from "node:test"; + +import { initRenderer, renderMarkdown } from "./renderer.ts"; + +const render = (md: string) => { + const r = initRenderer(); + return renderMarkdown(md, r).html; +}; + +test("bold with inline code (no underscore)", () => { + const html = render("**算出 `logits`,算出 `loss`。**"); + assert.match(html, /]*>logits<\/code>/); + assert.match(html, /]*>loss<\/code>/); +}); + +test("bold with inline code (contains underscore)", () => { + const html = render("**变成 `input_ids`。**"); + assert.match(html, /]*>input_ids<\/code>/); +}); + +test("emphasis with inline code", () => { + const html = render("*查看 `hidden_states`*"); + assert.match(html, /]*>hidden_states<\/code>/); +}); + +test("plain inline code (regression)", () => { + const html = render("`lm_head`"); + assert.match(html, /]*>lm_head<\/code>/); +}); + +test("bold without code (regression)", () => { + const html = render("**纯粗体文本**"); + assert.match(html, /]*>纯粗体文本<\/strong>/); + assert.doesNotMatch(html, / { + const html = render("**``a`b``**"); + assert.match(html, /]*>a`b<\/code>/); +}); + +test("emphasis with inline code containing backticks", () => { + const html = render("*``a`b``*"); + assert.match(html, /]*>]*>a`b<\/code><\/em>/); +}); + +test("bold with inline code containing consecutive backticks", () => { + const html = render("**```a``b```**"); + assert.match(html, /]*>a``b<\/code>/); +}); + +test("bold with inline code containing only backticks", () => { + const html = render("**```` `` ````**"); + assert.match(html, /]*>``<\/code>/); +}); + +test("bold with inline code containing only spaces", () => { + const oneSpace = render("**`` ``**"); + assert.match(oneSpace, /]*> <\/code>/); + + const twoSpaces = render("**`` ``**"); + assert.match(twoSpaces, /]*> <\/code>/); +}); diff --git a/skills/baoyu-post-to-wechat/scripts/vendor/baoyu-md/src/renderer.ts b/skills/baoyu-post-to-wechat/scripts/vendor/baoyu-md/src/renderer.ts index 7a1234c..2549737 100644 --- a/skills/baoyu-post-to-wechat/scripts/vendor/baoyu-md/src/renderer.ts +++ b/skills/baoyu-post-to-wechat/scripts/vendor/baoyu-md/src/renderer.ts @@ -109,6 +109,13 @@ function parseFrontMatterAndContent(markdownText: string): ParseResult { } } +function wrapInlineCode(value: string): string { + const runs = value.match(/`+/g); + const fence = "`".repeat(Math.max(...(runs?.map((run) => run.length) ?? [0])) + 1); + const padding = /^ *$/.test(value) ? "" : " "; + return `${fence}${padding}${value}${padding}${fence}`; +} + export function initRenderer(opts: IOpts = {}): RendererAPI { const footnotes: [number, string, string][] = []; let footnoteIndex = 0; @@ -369,6 +376,7 @@ function preprocessCjkEmphasis(markdown: string): string { const tree = processor.parse(markdown); const extractText = (node: any): string => { if (node.type === "text") return node.value; + if (node.type === "inlineCode") return wrapInlineCode(node.value); if (node.children) return node.children.map(extractText).join(""); return ""; }; diff --git a/skills/baoyu-post-to-weibo/scripts/vendor/baoyu-md/src/renderer.test.ts b/skills/baoyu-post-to-weibo/scripts/vendor/baoyu-md/src/renderer.test.ts new file mode 100644 index 0000000..702804c --- /dev/null +++ b/skills/baoyu-post-to-weibo/scripts/vendor/baoyu-md/src/renderer.test.ts @@ -0,0 +1,64 @@ +import assert from "node:assert/strict"; +import test from "node:test"; + +import { initRenderer, renderMarkdown } from "./renderer.ts"; + +const render = (md: string) => { + const r = initRenderer(); + return renderMarkdown(md, r).html; +}; + +test("bold with inline code (no underscore)", () => { + const html = render("**算出 `logits`,算出 `loss`。**"); + assert.match(html, /]*>logits<\/code>/); + assert.match(html, /]*>loss<\/code>/); +}); + +test("bold with inline code (contains underscore)", () => { + const html = render("**变成 `input_ids`。**"); + assert.match(html, /]*>input_ids<\/code>/); +}); + +test("emphasis with inline code", () => { + const html = render("*查看 `hidden_states`*"); + assert.match(html, /]*>hidden_states<\/code>/); +}); + +test("plain inline code (regression)", () => { + const html = render("`lm_head`"); + assert.match(html, /]*>lm_head<\/code>/); +}); + +test("bold without code (regression)", () => { + const html = render("**纯粗体文本**"); + assert.match(html, /]*>纯粗体文本<\/strong>/); + assert.doesNotMatch(html, / { + const html = render("**``a`b``**"); + assert.match(html, /]*>a`b<\/code>/); +}); + +test("emphasis with inline code containing backticks", () => { + const html = render("*``a`b``*"); + assert.match(html, /]*>]*>a`b<\/code><\/em>/); +}); + +test("bold with inline code containing consecutive backticks", () => { + const html = render("**```a``b```**"); + assert.match(html, /]*>a``b<\/code>/); +}); + +test("bold with inline code containing only backticks", () => { + const html = render("**```` `` ````**"); + assert.match(html, /]*>``<\/code>/); +}); + +test("bold with inline code containing only spaces", () => { + const oneSpace = render("**`` ``**"); + assert.match(oneSpace, /]*> <\/code>/); + + const twoSpaces = render("**`` ``**"); + assert.match(twoSpaces, /]*> <\/code>/); +}); diff --git a/skills/baoyu-post-to-weibo/scripts/vendor/baoyu-md/src/renderer.ts b/skills/baoyu-post-to-weibo/scripts/vendor/baoyu-md/src/renderer.ts index 7a1234c..2549737 100644 --- a/skills/baoyu-post-to-weibo/scripts/vendor/baoyu-md/src/renderer.ts +++ b/skills/baoyu-post-to-weibo/scripts/vendor/baoyu-md/src/renderer.ts @@ -109,6 +109,13 @@ function parseFrontMatterAndContent(markdownText: string): ParseResult { } } +function wrapInlineCode(value: string): string { + const runs = value.match(/`+/g); + const fence = "`".repeat(Math.max(...(runs?.map((run) => run.length) ?? [0])) + 1); + const padding = /^ *$/.test(value) ? "" : " "; + return `${fence}${padding}${value}${padding}${fence}`; +} + export function initRenderer(opts: IOpts = {}): RendererAPI { const footnotes: [number, string, string][] = []; let footnoteIndex = 0; @@ -369,6 +376,7 @@ function preprocessCjkEmphasis(markdown: string): string { const tree = processor.parse(markdown); const extractText = (node: any): string => { if (node.type === "text") return node.value; + if (node.type === "inlineCode") return wrapInlineCode(node.value); if (node.children) return node.children.map(extractText).join(""); return ""; };