profileShare

rasmusjy / voicetask

Read-only snapshot

No repository description.

main default branch 105 files Expires Sep 13, 2026, 9:06 AM
parse.ts 1,371 bytes
1 export interface BlockerEntry {
2 id: string
3 summary: string
4 task: string | null
5 question: string
6 optionsConsidered: string | null
7 continuedWith: string | null
8 }
9
10 const ENTRY_HEADER = /^(B\d+):\s*(.*)$/
11 const FIELD_PATTERNS: Array<{ key: keyof Omit<BlockerEntry, 'id' | 'summary'>; pattern: RegExp }> = [
12 { key: 'task', pattern: /^-\s*Task:\s*(.*)$/ },
13 { key: 'question', pattern: /^-\s*Question:\s*(.*)$/ },
14 { key: 'optionsConsidered', pattern: /^-\s*Options considered:\s*(.*)$/ },
15 { key: 'continuedWith', pattern: /^-\s*Continued with:\s*(.*)$/ },
16 ]
17
18 export function parseBlockedFile(content: string): BlockerEntry[] {
19 const blocks = content.split(/^##\s+/m).slice(1)
20 const entries: BlockerEntry[] = []
21
22 for (const block of blocks) {
23 const lines = block.split('\n')
24 const headerMatch = lines[0]?.match(ENTRY_HEADER)
25 if (!headerMatch) continue
26
27 const entry: BlockerEntry = {
28 id: headerMatch[1],
29 summary: headerMatch[2].trim(),
30 task: null,
31 question: '',
32 optionsConsidered: null,
33 continuedWith: null,
34 }
35
36 for (const line of lines.slice(1)) {
37 for (const { key, pattern } of FIELD_PATTERNS) {
38 const match = line.match(pattern)
39 if (match) {
40 entry[key] = match[1].trim()
41 break
42 }
43 }
44 }
45
46 entries.push(entry)
47 }
48
49 return entries
50 }
51