package issue import ( "regexp" "sort" "strings" ) var titleRe = regexp.MustCompile(`^#[ \t]+(.+?)[ \t]*\n`) // ParseMeta splits a file into its metadata block, title, and body. // // Values come back as the raw text that followed the colon. Lists are not // unpacked here: a foreign key that happens to look like a list must round // trip byte for byte, and the domain's own lists are unpacked by their // accessors. The title is the first `# ` heading below the block and is // stripped out of the body. func ParseMeta(text string) (meta map[string]string, title, body string) { meta = map[string]string{} rest := text if strings.HasPrefix(text, "---") { if end := strings.Index(text[3:], "\n---"); end != -1 { end += 3 for _, line := range strings.Split(strings.TrimSpace(text[3:end]), "\n") { k, v, ok := strings.Cut(line, ":") if !ok { continue } meta[strings.TrimSpace(k)] = strings.TrimSpace(v) } rest = text[end+4:] } } rest = strings.TrimLeft(rest, "\n") if m := titleRe.FindStringSubmatchIndex(rest); m != nil { title = strings.TrimSpace(rest[m[2]:m[3]]) rest = strings.TrimLeft(rest[m[1]:], "\n") } return meta, title, rest } // RenderMeta writes the block back: domain keys in DomainKeys order, foreign // keys after them, sorted. Lists stay on one line so grep sees them whole. func RenderMeta(meta map[string]string) string { var foreign []string for k := range meta { if !isDomainKey(k) { foreign = append(foreign, k) } } sort.Strings(foreign) lines := []string{"---"} for _, k := range append(append([]string{}, DomainKeys...), foreign...) { if v, ok := meta[k]; ok { lines = append(lines, k+": "+v) } } return strings.Join(append(lines, "---"), "\n") } // splitList unpacks the inline `[a, b]` form, and a bare comma-separated value // too: a hand-written `labels: type/bug` is the same statement as // `labels: [type/bug]` and the format does not make an operator care. func splitList(v string) []string { v = strings.TrimSpace(v) if strings.HasPrefix(v, "[") && strings.HasSuffix(v, "]") { v = v[1 : len(v)-1] } var out []string for _, part := range strings.Split(v, ",") { if part = strings.TrimSpace(part); part != "" { out = append(out, part) } } return out } func renderList(xs []string) string { return "[" + strings.Join(xs, ", ") + "]" }