


























@@ -3,11 +3,6 @@ import { md, toSanitizedMarkdownHtml } from "./markdown.ts";
3344describe("toSanitizedMarkdownHtml", () => {
55// ── Original tests from before markdown-it migration ──
6-it("renders basic markdown", () => {
7-const html = toSanitizedMarkdownHtml("Hello **world**");
8-expect(html).toContain("<strong>world</strong>");
9-});
10-116it("strips scripts and unsafe links", () => {
127const html = toSanitizedMarkdownHtml(
138[
@@ -23,146 +18,6 @@ describe("toSanitizedMarkdownHtml", () => {
2318expect(html).toContain("https://example.com");
2419});
252026-it("renders fenced code blocks", () => {
27-const html = toSanitizedMarkdownHtml(["```ts", "console.log(1)", "```"].join("\n"));
28-expect(html).toContain("<pre>");
29-expect(html).toContain("<code");
30-expect(html).toContain("console.log(1)");
31-});
32-33-it("flattens remote markdown images into alt text", () => {
34-const html = toSanitizedMarkdownHtml("");
35-expect(html).not.toContain("<img");
36-expect(html).toContain("Alt text");
37-});
38-39-it("preserves base64 data URI images (#15437)", () => {
40-const html = toSanitizedMarkdownHtml("");
41-expect(html).toContain("<img");
42-expect(html).toContain('class="markdown-inline-image"');
43-expect(html).toContain("data:image/png;base64,");
44-});
45-46-it("flattens non-data markdown image urls", () => {
47-const html = toSanitizedMarkdownHtml(")");
48-expect(html).not.toContain("<img");
49-expect(html).not.toContain("javascript:");
50-expect(html).toContain("X");
51-});
52-53-it("uses a plain fallback label for unlabeled markdown images", () => {
54-const html = toSanitizedMarkdownHtml("");
55-expect(html).not.toContain("<img");
56-expect(html).toContain("image");
57-});
58-59-it("renders GFM markdown tables (#20410)", () => {
60-const md = [
61-"| Feature | Status |",
62-"|---------|--------|",
63-"| Tables | ✅ |",
64-"| Borders | ✅ |",
65-].join("\n");
66-const html = toSanitizedMarkdownHtml(md);
67-expect(html).toContain("<table");
68-expect(html).toContain("<thead");
69-expect(html).toContain("<th>");
70-expect(html).toContain("Feature");
71-expect(html).toContain("Tables");
72-expect(html).not.toContain("|---------|");
73-});
74-75-it("renders GFM tables surrounded by text (#20410)", () => {
76-const md = [
77-"Text before.",
78-"",
79-"| Col1 | Col2 |",
80-"|------|------|",
81-"| A | B |",
82-"",
83-"Text after.",
84-].join("\n");
85-const html = toSanitizedMarkdownHtml(md);
86-expect(html).toContain("<table");
87-expect(html).toContain("Col1");
88-expect(html).toContain("Col2");
89-// Pipes from table delimiters must not appear as raw text
90-expect(html).not.toContain("|------|");
91-});
92-93-it("does not throw on deeply nested emphasis markers (#36213)", () => {
94-// Pathological patterns that can trigger catastrophic backtracking / recursion
95-const nested = "*".repeat(500) + "text" + "*".repeat(500);
96-expect(() => toSanitizedMarkdownHtml(nested)).not.toThrow();
97-const html = toSanitizedMarkdownHtml(nested);
98-expect(html).toContain("text");
99-});
100-101-it("does not throw on deeply nested brackets (#36213)", () => {
102-const nested = "[".repeat(200) + "link" + "]".repeat(200) + "(" + "x".repeat(200) + ")";
103-expect(() => toSanitizedMarkdownHtml(nested)).not.toThrow();
104-const html = toSanitizedMarkdownHtml(nested);
105-expect(html).toContain("link");
106-});
107-108-it("keeps oversized plain-text replies readable instead of forcing code-block chrome", () => {
109-const input =
110-Array.from(
111-{ length: 320 },
112-(_, i) => `Paragraph ${i + 1}: ${"Long plain-text reply. ".repeat(8)}`,
113-).join("\n\n") + "\n";
114-115-const html = toSanitizedMarkdownHtml(input);
116-117-expect(html).not.toContain('<pre class="code-block">');
118-expect(html).toContain('class="markdown-plain-text-fallback"');
119-expect(html).toContain("Paragraph 1:");
120-expect(html).toContain("Paragraph 320:");
121-});
122-123-it("preserves indentation in oversized plain-text replies", () => {
124-const input = `${"Header line\n".repeat(5000)}\n indented log line\n deeper indent`;
125-const html = toSanitizedMarkdownHtml(input);
126-127-expect(html).toContain('class="markdown-plain-text-fallback"');
128-expect(html).toContain(" indented log line");
129-expect(html).toContain(" deeper indent");
130-});
131-132-it("exercises the cached oversized fallback branch", () => {
133-const input =
134-Array.from(
135-{ length: 240 },
136-(_, i) => `Paragraph ${i + 1}: ${"Cacheable long reply. ".repeat(8)}`,
137-).join("\n\n") + "\n";
138-139-expect(input.length).toBeGreaterThan(40_000);
140-expect(input.length).toBeLessThan(50_000);
141-142-const first = toSanitizedMarkdownHtml(input);
143-const second = toSanitizedMarkdownHtml(input);
144-145-expect(first).toContain('class="markdown-plain-text-fallback"');
146-expect(second).toBe(first);
147-});
148-149-it("falls back to escaped plain text if md.render throws (#36213)", () => {
150-const renderSpy = vi.spyOn(md, "render").mockImplementation(() => {
151-throw new Error("forced render failure");
152-});
153-const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
154-const input = `Fallback **probe** ${Date.now()}`;
155-try {
156-const html = toSanitizedMarkdownHtml(input);
157-expect(html).toContain('<pre class="code-block">');
158-expect(html).toContain("Fallback **probe**");
159-expect(warnSpy).toHaveBeenCalledOnce();
160-} finally {
161-renderSpy.mockRestore();
162-warnSpy.mockRestore();
163-}
164-});
165-16621// ── Additional tests for markdown-it migration ──
16722describe("www autolinks", () => {
16823it("links www.example.com", () => {
@@ -474,11 +329,22 @@ describe("toSanitizedMarkdownHtml", () => {
474329expect(html).toContain("<s>deleted</s>");
475330});
476331477-it("renders tables", () => {
478-const md = "| A | B |\n|---|---|\n| 1 | 2 |";
332+it("renders tables surrounded by text", () => {
333+const md = [
334+"Text before.",
335+"",
336+"| A | B |",
337+"|---|---|",
338+"| 1 | 2 |",
339+"",
340+"Text after.",
341+].join("\n");
479342const html = toSanitizedMarkdownHtml(md);
480343expect(html).toContain("<table");
481344expect(html).toContain("<th>");
345+expect(html).toContain("Text before.");
346+expect(html).toContain("Text after.");
347+expect(html).not.toContain("|---|");
482348});
483349484350it("renders basic markdown", () => {
@@ -617,9 +483,12 @@ describe("toSanitizedMarkdownHtml", () => {
617483});
618484619485it("caches oversized fallback results", () => {
620-const input = Array.from({ length: 240 }, (_, i) => `P${i}`).join("\n\n") + "x".repeat(35000);
486+const input =
487+Array.from({ length: 240 }, (_, i) => `P${i}`).join("\n\n") + "x".repeat(45_000);
621488const first = toSanitizedMarkdownHtml(input);
622489const second = toSanitizedMarkdownHtml(input);
490+expect(input.length).toBeGreaterThan(40_000);
491+expect(first).toContain('class="markdown-plain-text-fallback"');
623492expect(second).toBe(first);
624493});
625494此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。