summaryrefslogtreecommitdiffstats
path: root/internal/cms/simpletoml.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/cms/simpletoml.go')
-rw-r--r--internal/cms/simpletoml.go172
1 files changed, 172 insertions, 0 deletions
diff --git a/internal/cms/simpletoml.go b/internal/cms/simpletoml.go
new file mode 100644
index 0000000..af2dcc7
--- /dev/null
+++ b/internal/cms/simpletoml.go
@@ -0,0 +1,172 @@
+package cms
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+type simpleTable struct {
+ values map[string]string
+ lists map[string][]string
+}
+
+func parseSimpleTable(data string) (simpleTable, error) {
+ table := simpleTable{
+ values: map[string]string{},
+ lists: map[string][]string{},
+ }
+
+ for lineNo, raw := range strings.Split(data, "\n") {
+ line := strings.TrimSpace(raw)
+ if line == "" || strings.HasPrefix(line, "#") || strings.HasPrefix(line, "[[") {
+ continue
+ }
+ key, rawValue, ok := strings.Cut(line, "=")
+ if !ok {
+ return table, fmt.Errorf("line %d: expected key = value", lineNo+1)
+ }
+ key = strings.TrimSpace(key)
+ rawValue = strings.TrimSpace(rawValue)
+ if key == "" {
+ return table, fmt.Errorf("line %d: empty key", lineNo+1)
+ }
+ if strings.HasPrefix(rawValue, "[") {
+ list, err := parseStringList(rawValue)
+ if err != nil {
+ return table, fmt.Errorf("line %d: %w", lineNo+1, err)
+ }
+ table.lists[key] = list
+ continue
+ }
+ value, err := parseScalar(rawValue)
+ if err != nil {
+ return table, fmt.Errorf("line %d: %w", lineNo+1, err)
+ }
+ table.values[key] = value
+ }
+
+ return table, nil
+}
+
+func parseMetadata(data string) (simpleTable, error) {
+ table, err := parseSimpleTable(data)
+ if err == nil {
+ return table, nil
+ }
+ yamlTable, yamlErr := parseSimpleYAMLTable(data)
+ if yamlErr == nil {
+ return yamlTable, nil
+ }
+ return table, err
+}
+
+func parseSimpleYAMLTable(data string) (simpleTable, error) {
+ table := simpleTable{
+ values: map[string]string{},
+ lists: map[string][]string{},
+ }
+
+ for lineNo, raw := range strings.Split(data, "\n") {
+ line := strings.TrimSpace(raw)
+ if line == "" || strings.HasPrefix(line, "#") {
+ continue
+ }
+ key, rawValue, ok := strings.Cut(line, ":")
+ if !ok {
+ return table, fmt.Errorf("line %d: expected key: value", lineNo+1)
+ }
+ key = strings.TrimSpace(key)
+ rawValue = strings.TrimSpace(rawValue)
+ if key == "" {
+ return table, fmt.Errorf("line %d: empty key", lineNo+1)
+ }
+ if strings.HasPrefix(rawValue, "[") {
+ list, err := parseStringList(rawValue)
+ if err != nil {
+ return table, fmt.Errorf("line %d: %w", lineNo+1, err)
+ }
+ table.lists[key] = list
+ continue
+ }
+ if key == "tags" && strings.Contains(rawValue, ",") {
+ table.lists[key] = splitCommaList(rawValue)
+ continue
+ }
+ value, err := parseScalar(rawValue)
+ if err != nil {
+ return table, fmt.Errorf("line %d: %w", lineNo+1, err)
+ }
+ table.values[key] = value
+ }
+
+ return table, nil
+}
+
+func parseScalar(raw string) (string, error) {
+ raw = strings.TrimSpace(raw)
+ if raw == "" {
+ return "", nil
+ }
+ if strings.HasPrefix(raw, "\"") {
+ value, err := strconv.Unquote(raw)
+ if err != nil {
+ return "", err
+ }
+ return value, nil
+ }
+ return raw, nil
+}
+
+func splitCommaList(value string) []string {
+ var out []string
+ for _, part := range strings.Split(value, ",") {
+ part = strings.TrimSpace(part)
+ if part != "" {
+ out = append(out, part)
+ }
+ }
+ return out
+}
+
+func parseStringList(raw string) ([]string, error) {
+ raw = strings.TrimSpace(raw)
+ if !strings.HasPrefix(raw, "[") || !strings.HasSuffix(raw, "]") {
+ return nil, fmt.Errorf("expected string list")
+ }
+ raw = strings.TrimSpace(strings.TrimSuffix(strings.TrimPrefix(raw, "["), "]"))
+ if raw == "" {
+ return nil, nil
+ }
+
+ var values []string
+ for _, part := range strings.Split(raw, ",") {
+ value, err := parseScalar(strings.TrimSpace(part))
+ if err != nil {
+ return nil, err
+ }
+ if value != "" {
+ values = append(values, value)
+ }
+ }
+ return values, nil
+}
+
+func formatString(value string) string {
+ return strconv.Quote(value)
+}
+
+func formatStringList(values []string) string {
+ quoted := make([]string, 0, len(values))
+ for _, value := range values {
+ quoted = append(quoted, strconv.Quote(value))
+ }
+ return "[" + strings.Join(quoted, ", ") + "]"
+}
+
+func boolString(value bool) string {
+ if value {
+ return "true"
+ }
+ return "false"
+}