package changelog import ( "bytes" "encoding/json" "errors" "fmt" "io/fs" "os" "strings" ) // LoadPeople reads people.json, a map from address to display name. // Addresses are matched case-insensitively. func LoadPeople(path string) (People, error) { raw, err := os.ReadFile(path) if err != nil { return nil, err } var m map[string]string if err := json.Unmarshal(raw, &m); err != nil { return nil, fmt.Errorf("%s: %w", path, err) } p := People{} for k, v := range m { if k == "//" { continue } p[strings.ToLower(k)] = v } return p, nil } // LoadLinks reads changelog-links.json. A missing file is no links. func LoadLinks(path string) (Links, error) { raw, err := os.ReadFile(path) if errors.Is(err, fs.ErrNotExist) { return Links{}, nil } if err != nil { return nil, err } var m map[string]json.RawMessage if err := json.Unmarshal(raw, &m); err != nil { return nil, fmt.Errorf("%s: %w", path, err) } l := Links{} for tag, v := range m { if tag == "//" { continue } var byLead map[string][]string if err := json.Unmarshal(v, &byLead); err != nil { return nil, fmt.Errorf("%s: %s: %w", path, tag, err) } l[tag] = byLead } return l, nil } // Load reads a committed changelog.json. func Load(path string) (*Changelog, error) { raw, err := os.ReadFile(path) if err != nil { return nil, err } var c Changelog dec := json.NewDecoder(bytes.NewReader(raw)) dec.DisallowUnknownFields() if err := dec.Decode(&c); err != nil { return nil, fmt.Errorf("%s: %w", path, err) } return &c, nil } // Marshal is the committed form: indented, no HTML escaping (the notes // carry "" placeholders), and a trailing newline. func Marshal(c *Changelog) ([]byte, error) { var b bytes.Buffer enc := json.NewEncoder(&b) enc.SetEscapeHTML(false) enc.SetIndent("", " ") if err := enc.Encode(c); err != nil { return nil, err } return b.Bytes(), nil }