754 lines · 20.1 KB · TypeScript
RawDownload
import { describe, expect, it } from "vite-plus/test";import type { MarkdownNode } from "react-native-nitro-markdown/headless"; import {  nativeMarkdownChunkSpacing,  nativeMarkdownDocumentChunks,  nativeMarkdownDocumentRuns,  nativeMarkdownListItemBlocks,  nativeMarkdownTextRuns,  nativeMarkdownWithPreservedSoftBreaks,} from "@t3tools/mobile-markdown-text/markdown"; describe("nativeMarkdownTextRuns", () => {  it("preserves inline emphasis and code styles", () => {    const node: MarkdownNode = {      type: "paragraph",      children: [        { type: "text", content: "plain " },        { type: "bold", children: [{ type: "text", content: "bold" }] },        { type: "text", content: " " },        { type: "code_inline", content: "const value = 1" },      ],    };     expect(nativeMarkdownTextRuns(node)).toEqual([      { text: "plain " },      { text: "bold", bold: true },      { text: " " },      { text: "const value = 1", code: true },    ]);  });   it("normalizes external and file links for native presentation", () => {    const node: MarkdownNode = {      type: "paragraph",      children: [        {          type: "link",          href: "https://example.com/docs",          children: [{ type: "text", content: "Docs" }],        },        { type: "text", content: " " },        {          type: "link",          href: "file:///repo/README.md#L12",          children: [{ type: "text", content: "ignored label" }],        },      ],    };     expect(nativeMarkdownTextRuns(node)).toEqual([      {        text: "Docs",        href: "https://example.com/docs",        externalHost: "example.com",      },      { text: " " },      {        text: "README.md:12",        href: "file:///repo/README.md#L12",        fileIcon: "readme",      },    ]);  });   it("keeps hard breaks and collapses soft breaks", () => {    const node: MarkdownNode = {      type: "paragraph",      children: [        { type: "text", content: "first" },        { type: "soft_break" },        { type: "text", content: "second" },        { type: "line_break" },        { type: "text", content: "third" },      ],    };     expect(nativeMarkdownTextRuns(node)).toEqual([{ text: "first second\nthird" }]);  });   it("can preserve soft breaks for authored user messages", () => {    const node: MarkdownNode = {      type: "paragraph",      children: [        { type: "text", content: "first" },        { type: "soft_break" },        { type: "text", content: "second" },      ],    };     expect(nativeMarkdownTextRuns(nativeMarkdownWithPreservedSoftBreaks(node))).toEqual([      { text: "first\nsecond" },    ]);  });   it("normalizes common inline HTML and entities", () => {    const node: MarkdownNode = {      type: "paragraph",      children: [        { type: "text", content: "Less than: &lt; " },        { type: "html_inline", content: "<kbd>" },        { type: "text", content: "⌘" },        { type: "html_inline", content: "</kbd>" },        { type: "html_inline", content: "<br />" },        { type: "html_inline", content: "<mark>highlighted</mark>" },      ],    };     expect(nativeMarkdownTextRuns(node)).toEqual([{ text: "Less than: < ⌘\nhighlighted" }]);  });   it("normalizes double-encoded entities and inline tags emitted as text", () => {    const node: MarkdownNode = {      type: "paragraph",      children: [        {          type: "text",          content:            "Keyboard: <kbd>⌘</kbd> + <kbd>K</kbd>; Less than: &amp;lt;; Greater than: &amp;gt;",        },      ],    };     expect(nativeMarkdownTextRuns(node)).toEqual([      { text: "Keyboard: ⌘ + K; Less than: <; Greater than: >" },    ]);  });   it("reads inline content from nested text nodes", () => {    const node: MarkdownNode = {      type: "paragraph",      children: [        {          type: "text",          children: [{ type: "text", content: "Plain text" }],        },        { type: "text", content: " and " },        {          type: "code_inline",          children: [{ type: "text", content: "inline code" }],        },      ],    };     expect(nativeMarkdownTextRuns(node)).toEqual([      { text: "Plain text and " },      { text: "inline code", code: true },    ]);  });}); describe("nativeMarkdownDocumentRuns", () => {  it("decorates known skill references as selectable skill links", () => {    const node: MarkdownNode = {      type: "document",      children: [        {          type: "paragraph",          children: [{ type: "text", content: "Use $ui for this." }],        },      ],    };     expect(nativeMarkdownDocumentRuns(node, [{ name: "ui", displayName: "UI" }])).toEqual([      { text: "Use ", role: "body" },      {        text: "$ui",        role: "body",        skillName: "ui",        skillLabel: "UI",      },      { text: " for this.", role: "body" },    ]);  });   it("leaves unknown skill-like text unchanged", () => {    const node: MarkdownNode = {      type: "document",      children: [        {          type: "paragraph",          children: [{ type: "text", content: "Use $unknown for this." }],        },      ],    };     expect(nativeMarkdownDocumentRuns(node, [])).toEqual([      { text: "Use $unknown for this.", role: "body" },    ]);  });   it("keeps headings, paragraphs, and lists in one continuous document", () => {    const node: MarkdownNode = {      type: "document",      children: [        {          type: "heading",          level: 1,          children: [{ type: "text", content: "Header One" }],        },        {          type: "paragraph",          children: [            { type: "text", content: "A paragraph with " },            { type: "bold", children: [{ type: "text", content: "bold text" }] },            { type: "text", content: "." },          ],        },        {          type: "list",          ordered: false,          children: [            {              type: "list_item",              children: [                {                  type: "paragraph",                  children: [{ type: "text", content: "First item" }],                },              ],            },            {              type: "list_item",              children: [                {                  type: "paragraph",                  children: [{ type: "text", content: "Second item" }],                },              ],            },          ],        },      ],    };     const runs = nativeMarkdownDocumentRuns(node);    expect(runs.map((run) => run.text).join("")).toBe(      "Header One\n\nA paragraph with bold text.\n\n•\tFirst item\n•\tSecond item",    );    expect(runs).toContainEqual({      text: "Header One\n",      role: "heading",      headingLevel: 1,    });    expect(runs).toContainEqual({      text: "bold text",      bold: true,      role: "body",    });    expect(runs).toContainEqual({      text: "•\t",      role: "list-marker",      depth: 1,      firstLineHeadIndent: 0,      headIndent: 24,      paragraphSpacing: 2,    });  });   it("uses distinct section, heading-content, and body spacing", () => {    const node: MarkdownNode = {      type: "document",      children: [        {          type: "paragraph",          children: [{ type: "text", content: "Intro" }],        },        {          type: "heading",          level: 2,          children: [{ type: "text", content: "Section" }],        },        {          type: "paragraph",          children: [{ type: "text", content: "First paragraph" }],        },        {          type: "paragraph",          children: [{ type: "text", content: "Second paragraph" }],        },      ],    };     expect(      nativeMarkdownDocumentRuns(node)        .filter((run) => run.role === "spacer")        .map((run) => run.spacing),    ).toEqual([20, 10, 12]);  });   it("renders tight list items whose inline nodes are direct children", () => {    const node: MarkdownNode = {      type: "document",      children: [        {          type: "list",          children: [            {              type: "list_item",              children: [                {                  type: "bold",                  children: [{ type: "text", content: "Finding:" }],                },                { type: "text", content: " details with " },                { type: "code_inline", content: "inline code" },                { type: "text", content: "." },              ],            },          ],        },      ],    };     expect(nativeMarkdownDocumentRuns(node)).toEqual([      {        text: "•\t",        role: "list-marker",        depth: 1,        firstLineHeadIndent: 0,        headIndent: 24,        paragraphSpacing: 2,      },      { text: "Finding:", bold: true, role: "body", depth: 1 },      { text: " details with ", role: "body", depth: 1 },      { text: "inline code", code: true, role: "body", depth: 1 },      { text: ".", role: "body", depth: 1 },    ]);  });   it("includes quotes and fenced code in the same selectable string", () => {    const node: MarkdownNode = {      type: "document",      children: [        {          type: "blockquote",          children: [            {              type: "paragraph",              children: [{ type: "text", content: "Read this" }],            },          ],        },        {          type: "code_block",          language: "ts",          content: "const answer = 42;",        },      ],    };     const runs = nativeMarkdownDocumentRuns(node);    expect(runs.map((run) => run.text).join("")).toBe("│\u00a0Read this\n\nTS\nconst answer = 42;");    expect(runs).toContainEqual({      text: "const answer = 42;",      code: true,      role: "code-block",    });  });   it("reads fenced code content from child text nodes", () => {    const node: MarkdownNode = {      type: "document",      children: [        {          type: "code_block",          language: "bash",          children: [{ type: "text", content: "pnpm install\n" }],        },      ],    };     expect(      nativeMarkdownDocumentRuns(node)        .map((run) => run.text)        .join(""),    ).toBe("BASH\npnpm install");  });}); describe("nativeMarkdownListItemBlocks", () => {  it("groups consecutive inline nodes into one paragraph block", () => {    const item: MarkdownNode = {      type: "list_item",      children: [        { type: "text", content: "Finding: " },        { type: "bold", children: [{ type: "text", content: "important" }] },        { type: "text", content: " details." },        {          type: "list",          children: [            {              type: "list_item",              children: [{ type: "text", content: "Nested" }],            },          ],        },        { type: "text", content: "Trailing prose." },      ],    };     expect(nativeMarkdownListItemBlocks(item)).toEqual([      {        type: "paragraph",        children: item.children?.slice(0, 3),      },      item.children?.[3],      {        type: "paragraph",        children: [item.children?.[4]],      },    ]);  });}); describe("nativeMarkdownDocumentChunks", () => {  it("keeps headings and plain lists in one selectable document", () => {    const document: MarkdownNode = {      type: "document",      children: [        {          type: "heading",          level: 2,          children: [{ type: "text", content: "Tasks" }],        },        {          type: "list",          children: [            {              type: "task_list_item",              checked: true,              children: [                {                  type: "paragraph",                  children: [{ type: "text", content: "Completed" }],                },              ],            },            {              type: "list_item",              children: [                {                  type: "paragraph",                  children: [{ type: "text", content: "Parent" }],                },                {                  type: "list",                  children: [                    {                      type: "list_item",                      children: [                        {                          type: "paragraph",                          children: [{ type: "text", content: "Nested" }],                        },                      ],                    },                  ],                },              ],            },          ],        },      ],    };     const chunks = nativeMarkdownDocumentChunks(document);    expect(chunks).toHaveLength(1);    expect(chunks[0]).toMatchObject({ kind: "selectable" });    expect(      nativeMarkdownDocumentRuns(chunks[0]?.node ?? document)        .map((run) => run.text)        .join(""),    ).toBe("Tasks\n\n☑︎\tCompleted\n•\tParent\n◦\tNested");  });   it("aligns ordered markers while keeping the list in one selectable string", () => {    const document: MarkdownNode = {      type: "document",      children: [        {          type: "list",          ordered: true,          start: 9,          children: [            {              type: "list_item",              children: [{ type: "text", content: "Ninth" }],            },            {              type: "list_item",              children: [{ type: "text", content: "Tenth" }],            },          ],        },      ],    };     expect(      nativeMarkdownDocumentRuns(document)

Lines 1–500 of 754.