Files
openclaw/packages/markdown-core/src/code-spans.test.ts
licheer-zte 97d3d60b51 fix(markdown): unify reasoning tag parsing (#113205)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-27 07:48:57 -04:00

123 lines
4.0 KiB
TypeScript

// Code span tests cover CommonMark block ownership and streamed lookup behavior.
import { describe, expect, it } from "vitest";
import { findMarkdownCodeSpans } from "./reasoning-tags.js";
describe("markdown-core code spans", () => {
function expectCodeRegionSlices(text: string, expectedSlices: readonly string[]) {
const regions = findMarkdownCodeSpans(text);
expect(regions).toHaveLength(expectedSlices.length);
expect(regions.map(([start, end]) => text.slice(start, end))).toEqual(expectedSlices);
}
function expectInsideCodeCase(params: {
positionSelector: (text: string, regionEnd: number) => number;
expected: boolean;
}) {
const text = "plain `code` done";
const regions = findMarkdownCodeSpans(text);
const regionEnd = regions[0]?.[1] ?? -1;
const position = params.positionSelector(text, regionEnd);
expect(regions.some(([start, end]) => position >= start && position < end)).toBe(
params.expected,
);
}
it.each([
{
name: "finds fenced and inline code regions without double-counting inline code inside fences",
text: ["before `inline` after", "```ts", "const a = `inside fence`;", "```", "tail"].join(
"\n",
),
expectedSlices: ["`inline`", "```ts\nconst a = `inside fence`;\n```"],
},
{
name: "accepts alternate fence markers and unterminated trailing fences",
text: "~~~js\nconsole.log(1)\n~~~\nplain\n```\nunterminated",
expectedSlices: ["~~~js\nconsole.log(1)\n~~~", "```\nunterminated"],
},
{
name: "keeps adjacent inline code outside fenced regions",
text: ["```ts", "const a = 1;", "```", "after `inline` tail"].join("\n"),
expectedSlices: ["```ts\nconst a = 1;\n```", "`inline`"],
},
] as const)("$name", ({ text, expectedSlices }) => {
expectCodeRegionSlices(text, expectedSlices);
});
it.each([
{
name: "requires equal backtick runs",
text: "before ```<think>private</think>`` after",
expectedSlices: [],
},
{
name: "keeps shorter runs inside a matching code span",
text: "before ``a`b`` after",
expectedSlices: ["``a`b``"],
},
{
name: "does not carry inline code from a paragraph into a list",
text: "paragraph `open\n- item `close",
expectedSlices: [],
},
{
name: "allows inline code across soft line breaks in one paragraph",
text: "paragraph `open\ncontinued` tail",
expectedSlices: ["`open\ncontinued`"],
},
{
name: "does not treat escaped backticks as delimiters",
text: "before \\`not code\\` after",
expectedSlices: [],
},
{
name: "does not join backticks across link destinations",
text: "[label](url`x) plain (y`) after",
expectedSlices: [],
},
{
name: "finds inline code inside GFM table cells",
text: "| a | b |\n| - | - |\n| `code` | y |",
expectedSlices: ["`code`"],
},
{
name: "finds fenced code nested in blockquotes",
text: "> ```xml\n> literal\n> ```",
expectedSlices: ["```xml\n> literal\n> ```"],
},
{
name: "finds indented code blocks",
text: " literal",
expectedSlices: [" literal"],
},
] as const)("follows CommonMark block ownership: $name", ({ text, expectedSlices }) => {
expectCodeRegionSlices(text, expectedSlices);
});
it.each([
{
name: "inside code",
positionSelector: (text: string) => text.indexOf("code"),
expected: true,
},
{
name: "outside code",
positionSelector: (text: string) => text.indexOf("plain"),
expected: false,
},
{
name: "at region end",
positionSelector: (_text: string, regionEnd: number) => regionEnd,
expected: false,
},
] as const)("reports whether positions are inside discovered regions: $name", (testCase) => {
expectInsideCodeCase(testCase);
});
it("walks deeply nested Markdown without exhausting the JavaScript stack", () => {
const input = `${"> ".repeat(10_000)}<think>x</think>`;
expect(findMarkdownCodeSpans(input)).toEqual([]);
});
});