Skip to content

Commit 906a6ed

Browse files
author
gluck
committed
outfit: a skill is keys, not a value holding an object
Every object-valued key on a real board came from one place: ContentEnvelope, written as one key per skill and one for the credo. 25 of 36 keys. They are keys now: skills.bossman.frontmatter skills.bossman.filePath system.credo.content system.credo.filePath A value the board cannot reach into must be rewritten whole to change one field, and it makes the keys a caller wrote differ from the paths the board holds -- which is why enumerating a board yielded 61 leaves for 36 keys. With the fields as keys the two are the same number. testdata/board-default.json keeps the old shape on purpose: it is what an older figaro wrote, and opening it is what the wire tests are for.
1 parent fb7d2e0 commit 906a6ed

2 files changed

Lines changed: 67 additions & 11 deletions

File tree

‎internal/outfit/outfit.go‎

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -396,12 +396,7 @@ func (o *Outfitter) flatten(prefix string, in map[string]any, out map[string]jso
396396
if err != nil {
397397
return fmt.Errorf("outfit: %s fileName=%q: %w", key, fn, err)
398398
}
399-
env := contentEnvelope(string(body), path)
400-
b, err := json.Marshal(env)
401-
if err != nil {
402-
return err
403-
}
404-
out[key] = b
399+
emitEnvelope(out, key, contentEnvelope(string(body), path))
405400
continue
406401
}
407402
if dn, ok := val["dirName"].(string); ok && len(val) == 1 {
@@ -433,11 +428,7 @@ func (o *Outfitter) flatten(prefix string, in map[string]any, out map[string]jso
433428
}
434429
}
435430
for name, env := range m {
436-
b, err := json.Marshal(env)
437-
if err != nil {
438-
return err
439-
}
440-
out[key+"."+name] = b
431+
emitEnvelope(out, key+"."+name, env)
441432
}
442433
continue
443434
}
@@ -608,3 +599,25 @@ func skillName(file string) (string, bool) {
608599
}
609600
return name, true
610601
}
602+
603+
// emitEnvelope writes an envelope as one key per field rather than one key
604+
// holding an object.
605+
//
606+
// A value the board cannot reach into is a value that must be rewritten whole
607+
// to change one field, and it makes the keys a caller wrote differ from the
608+
// paths the board holds. The fields are keys.
609+
func emitEnvelope(out map[string]json.RawMessage, prefix string, env ContentEnvelope) {
610+
put := func(field, v string) {
611+
if v == "" {
612+
return
613+
}
614+
b, err := json.Marshal(v)
615+
if err != nil {
616+
return
617+
}
618+
out[prefix+"."+field] = b
619+
}
620+
put("frontmatter", env.Frontmatter)
621+
put("content", env.Content)
622+
put("filePath", env.FilePath)
623+
}

‎internal/outfit/structural_test.go‎

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package outfit_test
2+
3+
import (
4+
"encoding/json"
5+
"os"
6+
"path/filepath"
7+
"sort"
8+
"testing"
9+
10+
"github.com/stretchr/testify/require"
11+
12+
"github.com/jack-work/figaro/internal/outfit"
13+
)
14+
15+
// A skill reaches the board as keys, not as one value holding an object.
16+
func TestSkillsArriveStructural(t *testing.T) {
17+
dir := t.TempDir()
18+
skills := filepath.Join(dir, "skills")
19+
require.NoError(t, os.MkdirAll(skills, 0o755))
20+
require.NoError(t, os.WriteFile(filepath.Join(skills, "alpha.md"),
21+
[]byte("---\nname: alpha\ndescription: A\n---\nbody"), 0o644))
22+
require.NoError(t, os.WriteFile(filepath.Join(dir, "credo.md"), []byte("the credo"), 0o644))
23+
require.NoError(t, os.MkdirAll(filepath.Join(dir, "outfits"), 0o755))
24+
require.NoError(t, os.WriteFile(filepath.Join(dir, "outfits", "top.toml"),
25+
[]byte("skills = { dirName = \"skills\" }\n[system]\ncredo = { fileName = \"credo.md\" }\n"), 0o644))
26+
27+
p, err := outfit.New(dir).Load("top")
28+
require.NoError(t, err)
29+
30+
var keys []string
31+
for _, e := range p.Entries() {
32+
keys = append(keys, e.Key)
33+
}
34+
sort.Strings(keys)
35+
t.Logf("keys: %v", keys)
36+
37+
for _, want := range []string{"skills.alpha.frontmatter", "skills.alpha.filePath", "system.credo.content"} {
38+
e, ok := p.Entry(want)
39+
require.True(t, ok, "%s must be its own key", want)
40+
var s string
41+
require.NoError(t, json.Unmarshal(e.New, &s), "%s must be a string, not an object", want)
42+
}
43+
}

0 commit comments

Comments
 (0)