File size: 2,538 Bytes
c2c8c8d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
export interface MarkdownSegment {
  type: 'text' | 'code';
  content?: string;
  filename?: string | null;
  language?: string;
  code?: string;
}

export function parseMarkdown(content: string): MarkdownSegment[] {
  const segments: MarkdownSegment[] = [];
  const lines = content.split('\n');
  
  let currentText = '';
  let inCodeBlock = false;
  let codeContent = '';
  let filename: string | null = null;
  let language = '';
  let nestingLevel = 0;

  for (let i = 0; i < lines.length; i++) {
    const line = lines[i];
    const trimmed = line.trim();
    const isBackticks = trimmed.startsWith('```');

    if (isBackticks) {
      if (!inCodeBlock) {
        inCodeBlock = true;
        language = trimmed.replace(/^`+/, '').trim();
        nestingLevel = 0;
        
        // Peek at previous text for filename e.g. **`file.ts`**
        const prevTextLines = currentText.trimEnd().split('\n');
        const lastPrevLine = prevTextLines[prevTextLines.length - 1] || '';
        const fileMatch = lastPrevLine.match(/\*\*\`?([^\`\n]+)\`?\*\*/);
        
        if (fileMatch) {
          filename = fileMatch[1];
          prevTextLines.pop();
          currentText = prevTextLines.join('\n');
        } else {
          filename = null;
        }

        if (currentText.trim()) {
          segments.push({ type: 'text', content: currentText.trim() });
        }
        currentText = '';
        codeContent = '';
      } else {
        // Distinguish between inner open (```bash) and close (```)
        const isInnerOpen = trimmed.length > 3 && trimmed !== '```';
        const isClose = /^`+$/.test(trimmed);

        if (isInnerOpen) {
          nestingLevel++;
          codeContent += line + '\n';
        } else if (isClose) {
          if (nestingLevel > 0) {
            nestingLevel--;
            codeContent += line + '\n';
          } else {
            inCodeBlock = false;
            segments.push({ type: 'code', filename, language, code: codeContent.trim() });
            codeContent = '';
            filename = null;
          }
        } else {
          codeContent += line + '\n';
        }
      }
    } else {
      if (inCodeBlock) {
        codeContent += line + '\n';
      } else {
        currentText += line + '\n';
      }
    }
  }

  if (inCodeBlock && codeContent.trim()) {
    segments.push({ type: 'code', filename, language, code: codeContent.trim() });
  } else if (currentText.trim()) {
    segments.push({ type: 'text', content: currentText.trim() });
  }

  return segments;
}