Skip to content
File

Blob: src/client/lib/ai/blocks.ts

typescript71 lines
1export type AiInlineContent = { type: "text"; text: string };
2 
3export type AiBlockContent =
4 | { type: "paragraph"; content?: AiInlineContent[] }
5 | { type: "bulletList"; content: AiListItemContent[] };
6 
7export interface AiListItemContent {
8 type: "listItem";
9 content: Array<{ type: "paragraph"; content?: AiInlineContent[] }>;
10}
11 
12const BULLET_LINE = /^\s*[-*]\s+(.*)$/;
13 
14export function parseAiBlocksFromText(raw: string): AiBlockContent[] {
15 const normalized = raw
16 .replace(/\r\n/g, "\n")
17 .replace(/[\t ]+\n/g, "\n")
18 .trim();
19 if (!normalized) return [];
20 
21 const segments = normalized.split(/\n{2,}/);
22 const blocks: AiBlockContent[] = [];
23 
24 for (const segment of segments) {
25 const lines = segment.split("\n");
26 const bulletItems: string[] = [];
27 let isAllBullets = lines.length > 0;
28 for (const line of lines) {
29 const match = BULLET_LINE.exec(line);
30 if (!match) {
31 isAllBullets = false;
32 break;
33 }
34 bulletItems.push(match[1].trim());
35 }
36 
37 if (isAllBullets && bulletItems.length > 0) {
38 blocks.push({
39 type: "bulletList",
40 content: bulletItems.map((text) => ({
41 type: "listItem",
42 content: [paragraphNode(text)],
43 })),
44 });
45 continue;
46 }
47 
48 const paragraphText = lines
49 .map((line) => line.trim())
50 .filter(Boolean)
51 .join(" ");
52 blocks.push(paragraphNode(paragraphText));
53 }
54 
55 return blocks;
56}
57 
58export function isSingleInlineParagraph(blocks: AiBlockContent[]): boolean {
59 return blocks.length === 1 && blocks[0].type === "paragraph";
60}
61 
62export function getInlineTextFromParagraph(block: AiBlockContent): string {
63 if (block.type !== "paragraph" || !block.content) return "";
64 return block.content.map((node) => node.text).join("");
65}
66 
67function paragraphNode(text: string): { type: "paragraph"; content?: AiInlineContent[] } {
68 if (!text) return { type: "paragraph" };
69 return { type: "paragraph", content: [{ type: "text", text }] };
70}