MCPcopy Create free account
hub / github.com/MiniCodeMonkey/chief / ParseMarkdownPRDFromString

Function ParseMarkdownPRDFromString

internal/prd/markdown.go:39–173  ·  view source on GitHub ↗

ParseMarkdownPRDFromString parses a PRD from a markdown string.

(content string)

Source from the content-addressed store, hash-verified

37
38// ParseMarkdownPRDFromString parses a PRD from a markdown string.
39func ParseMarkdownPRDFromString(content string) (*PRD, error) {
40 lines := strings.Split(content, "\n")
41 p := &PRD{}
42
43 type storyBuilder struct {
44 story UserStory
45 descLines []string
46 }
47
48 var current *storyBuilder
49 introStarted := false
50 introDone := false
51 autoPriority := float64(0)
52
53 flushStory := func() {
54 if current == nil {
55 return
56 }
57 // If no explicit Description, join collected prose lines
58 if current.story.Description == "" && len(current.descLines) > 0 {
59 current.story.Description = strings.Join(current.descLines, " ")
60 }
61 // Assign auto-priority if none was set
62 if current.story.Priority == 0 {
63 autoPriority++
64 current.story.Priority = autoPriority
65 } else if current.story.Priority > autoPriority {
66 autoPriority = current.story.Priority
67 }
68 p.UserStories = append(p.UserStories, current.story)
69 current = nil
70 }
71
72 for _, line := range lines {
73 trimmed := strings.TrimSpace(line)
74
75 // Check for project heading (# level only, not ## or ###)
76 if strings.HasPrefix(line, "# ") && !strings.HasPrefix(line, "## ") {
77 if m := projectHeadingRegex.FindStringSubmatch(trimmed); m != nil {
78 p.Project = strings.TrimSpace(m[1])
79 introStarted = true
80 continue
81 }
82 }
83
84 // Check for story heading (### ID: Title)
85 if m := storyHeadingRegex.FindStringSubmatch(trimmed); m != nil {
86 flushStory()
87 introDone = true
88 current = &storyBuilder{
89 story: UserStory{
90 ID: m[1],
91 Title: strings.TrimSpace(m[2]),
92 },
93 }
94 continue
95 }
96

Calls

no outgoing calls