feature/recipe_implementation #5

Merged
gmgauthier merged 54 commits from feature/recipe_implementation into master 2026-03-07 23:17:54 +00:00
Showing only changes of commit 852142730a - Show all commits

View File

@ -12,8 +12,8 @@ import (
) )
var ( var (
// stepRe still finds the headings (this one is solid)
stepRe = regexp.MustCompile(`(?m)^### Step (\d+): (.+)$`) stepRe = regexp.MustCompile(`(?m)^### Step (\d+): (.+)$`)
subRe = regexp.MustCompile(`(?m)^(\*\*(?:Objective|Instructions|Expected output):\*\*)\s*(.+?)(?:\n\n|\n###|\z)`)
) )
func Load(path string, userParams map[string]any) (*Recipe, error) { func Load(path string, userParams map[string]any) (*Recipe, error) {
@ -45,7 +45,7 @@ func Load(path string, userParams map[string]any) (*Recipe, error) {
} }
} }
// Render templates // Render templates (so {{.package_path}} becomes "internal")
tpl, err := template.New("recipe").Parse(string(parts[2])) tpl, err := template.New("recipe").Parse(string(parts[2]))
if err != nil { if err != nil {
return nil, err return nil, err
@ -61,7 +61,7 @@ func Load(path string, userParams map[string]any) (*Recipe, error) {
r.Overview = strings.TrimSpace(body[:idx]) r.Overview = strings.TrimSpace(body[:idx])
} }
// Extract steps — split-based to guarantee no duplicates // Extract steps with robust multi-line parsing
matches := stepRe.FindAllStringSubmatch(body, -1) matches := stepRe.FindAllStringSubmatch(body, -1)
for i, m := range matches { for i, m := range matches {
stepNum := i + 1 stepNum := i + 1
@ -77,20 +77,42 @@ func Load(path string, userParams map[string]any) (*Recipe, error) {
section := body[start:end] section := body[start:end]
step := Step{Number: stepNum, Title: title} step := Step{Number: stepNum, Title: title}
for _, sub := range subRe.FindAllStringSubmatch(section, -1) {
switch sub[1] { // Simple, reliable label-based parsing (handles multi-line + blank lines)
labels := []string{"**Objective:**", "**Instructions:**", "**Expected output:**"}
for _, label := range labels {
labelStart := strings.Index(section, label)
if labelStart == -1 {
continue
}
contentStart := labelStart + len(label)
contentEnd := len(section)
// Find next label or end of section
for _, nextLabel := range labels {
next := strings.Index(section[contentStart:], nextLabel)
if next != -1 {
contentEnd = contentStart + next
break
}
}
content := strings.TrimSpace(section[contentStart:contentEnd])
switch label {
case "**Objective:**": case "**Objective:**":
step.Objective = strings.TrimSpace(sub[2]) step.Objective = content
case "**Instructions:**": case "**Instructions:**":
step.Instructions = strings.TrimSpace(sub[2]) step.Instructions = content
case "**Expected output:**": case "**Expected output:**":
step.Expected = strings.TrimSpace(sub[2]) step.Expected = content
} }
} }
r.Steps = append(r.Steps, step) r.Steps = append(r.Steps, step)
} }
// Final summary = everything after the last step // Final summary (everything after last step)
if len(matches) > 0 { if len(matches) > 0 {
lastMatch := matches[len(matches)-1][0] lastMatch := matches[len(matches)-1][0]
lastIdx := strings.LastIndex(body, lastMatch) lastIdx := strings.LastIndex(body, lastMatch)