package gsp import ( "fmt" "sort" "strings" ) func (p PackResult) Markdown() string { var builder strings.Builder builder.WriteString("# GSP Context Pack\n\n") builder.WriteString(fmt.Sprintf("- Entry: `%s`\n", p.Entry)) if p.Intent != "" { builder.WriteString(fmt.Sprintf("- Intent: `%s`\n", p.Intent)) } if p.Stage != "" { builder.WriteString(fmt.Sprintf("- Stage: `%s`\n", p.Stage)) } builder.WriteString(fmt.Sprintf("- Units: `%d`\n", p.Summary.UnitCount)) if p.Summary.LinkCount > 0 { builder.WriteString(fmt.Sprintf("- Links: `%d`\n", p.Summary.LinkCount)) } if p.Summary.MinResolution != "" { builder.WriteString(fmt.Sprintf("- Resolution: `%s` to `%s`\n", p.Summary.MinResolution, p.Summary.MaxResolution)) } if p.Budget > 0 { builder.WriteString(fmt.Sprintf("- Budget: `%d`\n", p.Budget)) builder.WriteString(fmt.Sprintf("- Approx chars: `%d`\n", p.ApproxChars)) builder.WriteString(fmt.Sprintf("- Truncated: `%v`\n", p.Truncated)) } builder.WriteString("\n## Units\n\n") for _, unit := range p.Units { builder.WriteString(fmt.Sprintf("### %s\n\n", unit.DisplayTitle())) builder.WriteString(fmt.Sprintf("- id: `%s`\n", unit.ID)) if unit.Type != "" { builder.WriteString(fmt.Sprintf("- type: `%s`\n", unit.Type)) } if unit.Resolution != "" { builder.WriteString(fmt.Sprintf("- resolution: `%s`\n", unit.Resolution)) } if unit.Refines != "" { builder.WriteString(fmt.Sprintf("- refines: `%s`\n", unit.Refines)) } if len(unit.With) > 0 { var with []string for _, rel := range unit.With { with = append(with, "`"+rel.ID+"`") } sort.Strings(with) builder.WriteString("- with: " + strings.Join(with, ", ") + "\n") } if unit.Context != "" { builder.WriteString("\n") builder.WriteString(unit.Context) builder.WriteString("\n") } builder.WriteString("\n") } if len(p.Links) > 0 { builder.WriteString("## Links\n\n") for _, link := range p.Links { builder.WriteString(fmt.Sprintf("- `%s` %s\n", link.Owner, link.Path)) builder.WriteString(fmt.Sprintf(" - role: `%s`\n", link.Role)) builder.WriteString(fmt.Sprintf(" - kind: `%s`\n", link.Kind)) builder.WriteString(fmt.Sprintf(" - status: `%s`\n", link.Status)) } builder.WriteString("\n") } if len(p.Warnings) > 0 { builder.WriteString("## Warnings\n\n") for _, warning := range p.Warnings { builder.WriteString(fmt.Sprintf("- `%s`: %s\n", warning.Code, warning.Message)) } } return builder.String() } func (r ImpactResult) Markdown() string { var builder strings.Builder builder.WriteString("# GSP Impact\n\n") builder.WriteString(fmt.Sprintf("- Entry: `%s`\n", r.Entry)) builder.WriteString(fmt.Sprintf("- Direct affected: `%d`\n", r.Summary.DirectCount)) builder.WriteString(fmt.Sprintf("- Indirect affected: `%d`\n", r.Summary.IndirectCount)) builder.WriteString(fmt.Sprintf("- Max depth: `%d`\n", r.Summary.MaxDepth)) writeImpactSection(&builder, "Direct", r.Direct) writeImpactSection(&builder, "Indirect", r.Indirect) if len(r.Warnings) > 0 { builder.WriteString("## Warnings\n\n") for _, warning := range r.Warnings { builder.WriteString(fmt.Sprintf("- `%s`: %s\n", warning.Code, warning.Message)) } } return builder.String() } func writeImpactSection(builder *strings.Builder, title string, entries []ImpactEntry) { builder.WriteString("\n## " + title + "\n\n") if len(entries) == 0 { builder.WriteString("None.\n") return } for _, entry := range entries { label := entry.Title if label == "" { label = entry.ID } builder.WriteString(fmt.Sprintf("- `%s` %s", entry.ID, label)) if entry.Kind != "" || entry.Via != "" { builder.WriteString(fmt.Sprintf(" via `%s` `%s`", entry.Kind, entry.Via)) } if entry.Type != "" { builder.WriteString(fmt.Sprintf(" type `%s`", entry.Type)) } if entry.Resolution != "" { builder.WriteString(fmt.Sprintf(" resolution `%s`", entry.Resolution)) } builder.WriteString("\n") } } func (u Unit) DisplayTitle() string { if strings.TrimSpace(u.Title) != "" { return u.Title } return u.ID }