atagen

malice

public
Star0
Watch0
7ebc2472a9e309499f0bd7be196d0c1bc4add938
2
ssh://brewery@pls.lobotomise.me:33/atagen/malice.git
web/src/lib/code.tsTypescript38 lines1.2 KB
1
export type CodeSegment =
2
  | { kind: 'text'; text: string }
3
  | { kind: 'inline'; text: string }
4
  | { kind: 'block'; text: string; lang: string | null };
5
6
const FENCE = /```([^\s`]*)[^\S\n]*\n?([\s\S]*?)\n?```/g;
7
const INLINE = /`([^`\n]+)`/g;
8
9
function splitInline(text: string, out: CodeSegment[]): void {
10
  let last = 0;
11
  for (const m of text.matchAll(INLINE)) {
12
    if (m.index > last) out.push({ kind: 'text', text: text.slice(last, m.index) });
13
    out.push({ kind: 'inline', text: m[1] });
14
    last = m.index + m[0].length;
15
  }
16
  if (last < text.length) out.push({ kind: 'text', text: text.slice(last) });
17
}
18
19
export function parseCode(text: string): CodeSegment[] {
20
  const out: CodeSegment[] = [];
21
  if (!text.includes('`')) {
22
    if (text) out.push({ kind: 'text', text });
23
    return out;
24
  }
25
  let last = 0;
26
  for (const m of text.matchAll(FENCE)) {
27
    splitInline(text.slice(last, m.index), out);
28
    out.push({ kind: 'block', text: m[2], lang: m[1] || null });
29
    last = m.index + m[0].length;
30
    if (text[last] === '\n') last += 1;
31
  }
32
  splitInline(text.slice(last), out);
33
  return out;
34
}
35
36
export function hasCode(segments: CodeSegment[]): boolean {
37
  return segments.some((s) => s.kind !== 'text');
38
}