Skip to content

Commit 5607a1d

Browse files
committed
feat: add ID comment to bean front matter
- Include bean ID as YAML comment after opening `---` delimiter - Makes IDs easier to copy-paste when viewing bean files - Only renders comment when bean has an ID set - Add tests for ID comment rendering and roundtrip parsing
1 parent 769fba8 commit 5607a1d

File tree

3 files changed

+99
-0
lines changed

3 files changed

+99
-0
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
# beans-479f
3+
title: Add ID comment to bean front matter
4+
status: completed
5+
type: feature
6+
created_at: 2025-12-13T12:38:58Z
7+
updated_at: 2025-12-13T12:38:58Z
8+
---
9+
10+
When beans writes a bean file to disk, the YAML front matter now includes a comment with the bean ID (e.g., `# beans-kp3h`) right after the opening `---` delimiter. This makes it easier to copy-paste bean IDs when viewing files.

internal/bean/bean.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,11 @@ func (b *Bean) Render() ([]byte, error) {
198198

199199
var buf bytes.Buffer
200200
buf.WriteString("---\n")
201+
if b.ID != "" {
202+
buf.WriteString("# ")
203+
buf.WriteString(b.ID)
204+
buf.WriteString("\n")
205+
}
201206
buf.Write(fmBytes)
202207
buf.WriteString("---\n")
203208
if b.Body != "" {

internal/bean/bean_test.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1132,3 +1132,87 @@ func TestTagsRoundtrip(t *testing.T) {
11321132
})
11331133
}
11341134
}
1135+
1136+
func TestRenderWithIDComment(t *testing.T) {
1137+
tests := []struct {
1138+
name string
1139+
bean *Bean
1140+
expectComment string
1141+
}{
1142+
{
1143+
name: "with ID",
1144+
bean: &Bean{
1145+
ID: "beans-abc123",
1146+
Title: "Test Bean",
1147+
Status: "todo",
1148+
},
1149+
expectComment: "# beans-abc123",
1150+
},
1151+
{
1152+
name: "without ID",
1153+
bean: &Bean{
1154+
Title: "Test Bean",
1155+
Status: "todo",
1156+
},
1157+
expectComment: "",
1158+
},
1159+
}
1160+
1161+
for _, tt := range tests {
1162+
t.Run(tt.name, func(t *testing.T) {
1163+
output, err := tt.bean.Render()
1164+
if err != nil {
1165+
t.Fatalf("unexpected error: %v", err)
1166+
}
1167+
1168+
result := string(output)
1169+
1170+
if tt.expectComment != "" {
1171+
// Check that comment appears right after opening ---
1172+
expectedStart := "---\n" + tt.expectComment + "\n"
1173+
if !strings.HasPrefix(result, expectedStart) {
1174+
t.Errorf("expected output to start with %q\ngot:\n%s", expectedStart, result)
1175+
}
1176+
} else {
1177+
// When no ID, should not have a comment line
1178+
lines := strings.Split(result, "\n")
1179+
if len(lines) > 1 && strings.HasPrefix(lines[1], "#") {
1180+
t.Errorf("expected no comment line when ID is empty\ngot:\n%s", result)
1181+
}
1182+
}
1183+
})
1184+
}
1185+
}
1186+
1187+
func TestRenderWithIDCommentRoundtrip(t *testing.T) {
1188+
// Verify that the ID comment doesn't interfere with parsing
1189+
original := &Bean{
1190+
ID: "beans-xyz789",
1191+
Title: "Test Bean",
1192+
Status: "in-progress",
1193+
Body: "Some body content.",
1194+
}
1195+
1196+
rendered, err := original.Render()
1197+
if err != nil {
1198+
t.Fatalf("Render error: %v", err)
1199+
}
1200+
1201+
// Verify the comment is present
1202+
if !strings.Contains(string(rendered), "# beans-xyz789") {
1203+
t.Errorf("rendered output should contain ID comment\ngot:\n%s", rendered)
1204+
}
1205+
1206+
// Parse should work correctly (comment is ignored)
1207+
parsed, err := Parse(strings.NewReader(string(rendered)))
1208+
if err != nil {
1209+
t.Fatalf("Parse error: %v", err)
1210+
}
1211+
1212+
if parsed.Title != original.Title {
1213+
t.Errorf("Title roundtrip: got %q, want %q", parsed.Title, original.Title)
1214+
}
1215+
if parsed.Status != original.Status {
1216+
t.Errorf("Status roundtrip: got %q, want %q", parsed.Status, original.Status)
1217+
}
1218+
}

0 commit comments

Comments
 (0)