feat(wiki): add Aliases to Entry and read from YAML frontmatter

This commit is contained in:
Mathias Bergqvist
2026-04-23 15:57:16 +02:00
parent 9cc6c2d053
commit bf6f497d9d
4 changed files with 58 additions and 15 deletions

View File

@@ -32,23 +32,26 @@ func LoadInventory(brainDir string) (map[PageType][]Entry, error) {
} }
slug := strings.TrimSuffix(e.Name(), ".md") slug := strings.TrimSuffix(e.Name(), ".md")
path := filepath.Join(dir, e.Name()) path := filepath.Join(dir, e.Name())
title := readTitle(path, slug) title, aliases := readFrontmatter(path, slug)
result[pt] = append(result[pt], Entry{Slug: slug, Title: title, Type: pt}) result[pt] = append(result[pt], Entry{Slug: slug, Title: title, Aliases: aliases, Type: pt})
} }
} }
return result, nil return result, nil
} }
// readTitle extracts the title from YAML frontmatter, falling back to slug. // readFrontmatter extracts title and aliases from YAML frontmatter.
func readTitle(path, fallback string) string { // Falls back to slug for title and empty aliases on any error.
func readFrontmatter(path, fallbackSlug string) (title string, aliases []string) {
title = fallbackSlug
f, err := os.Open(path) f, err := os.Open(path)
if err != nil { if err != nil {
return fallback return
} }
defer f.Close() defer f.Close()
scanner := bufio.NewScanner(f) scanner := bufio.NewScanner(f)
inFM := false inFM := false
inAliases := false
for scanner.Scan() { for scanner.Scan() {
line := scanner.Text() line := scanner.Text()
if strings.TrimSpace(line) == "---" { if strings.TrimSpace(line) == "---" {
@@ -56,14 +59,32 @@ func readTitle(path, fallback string) string {
inFM = true inFM = true
continue continue
} }
break break // end of frontmatter
} }
if inFM { if !inFM {
key, val, ok := strings.Cut(line, ":") continue
if ok && strings.TrimSpace(key) == "title" { }
return strings.Trim(strings.TrimSpace(val), `"'`)
// Detect alias list items (lines starting with " - ").
if inAliases {
trimmed := strings.TrimSpace(line)
if strings.HasPrefix(trimmed, "- ") {
aliases = append(aliases, strings.TrimPrefix(trimmed, "- "))
continue
} }
inAliases = false // end of alias block
}
key, val, ok := strings.Cut(line, ":")
if !ok {
continue
}
switch strings.TrimSpace(key) {
case "title":
title = strings.Trim(strings.TrimSpace(val), `"'`)
case "aliases":
inAliases = true
} }
} }
return fallback return
} }

View File

@@ -60,3 +60,24 @@ func TestLoadInventory_MissingDirsOk(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
assert.NotNil(t, inv) assert.NotNil(t, inv)
} }
func TestLoadInventory_ReadsAliases(t *testing.T) {
dir := t.TempDir()
require.NoError(t, os.MkdirAll(filepath.Join(dir, "wiki", "entities"), 0o755))
require.NoError(t, os.MkdirAll(filepath.Join(dir, "wiki", "concepts"), 0o755))
require.NoError(t, os.MkdirAll(filepath.Join(dir, "wiki", "sources"), 0o755))
require.NoError(t, os.WriteFile(
filepath.Join(dir, "wiki", "entities", "ryan-singer.md"),
[]byte("---\ntitle: Ryan Singer\naliases:\n - Singer\n - R. Singer\n---\n\n## Description\n\nDesigner.\n"),
0o644,
))
inv, err := LoadInventory(dir)
require.NoError(t, err)
require.Len(t, inv[PageTypeEntity], 1)
e := inv[PageTypeEntity][0]
assert.Equal(t, "Ryan Singer", e.Title)
assert.Equal(t, []string{"Singer", "R. Singer"}, e.Aliases)
}

View File

@@ -21,7 +21,7 @@ func Slug(title string) string {
case unicode.IsLetter(r) || unicode.IsDigit(r): case unicode.IsLetter(r) || unicode.IsDigit(r):
b.WriteRune(r) b.WriteRune(r)
prevHyphen = false prevHyphen = false
// all other characters (apostrophes, colons, dots, etc.) are dropped // all other characters (apostrophes, colons, dots, etc.) are dropped
} }
} }
return strings.TrimRight(b.String(), "-") return strings.TrimRight(b.String(), "-")

View File

@@ -18,7 +18,8 @@ type Page struct {
// Entry is a summary of an existing wiki page used to build the inventory. // Entry is a summary of an existing wiki page used to build the inventory.
type Entry struct { type Entry struct {
Slug string Slug string
Title string Title string
Type PageType Aliases []string
Type PageType
} }