Parse splits a dotted key path into its components, supporting TOML-style quoted segments so users can address keys that contain dots or special characters (e.g. codex.profiles."alibaba/glm-4.5".model).
(raw string)
| 11 | // quoted segments so users can address keys that contain dots or special |
| 12 | // characters (e.g. codex.profiles."alibaba/glm-4.5".model). |
| 13 | func Parse(raw string) ([]string, error) { |
| 14 | raw = strings.TrimSpace(raw) |
| 15 | if raw == "" { |
| 16 | return nil, fmt.Errorf("editorconfig: empty key path") |
| 17 | } |
| 18 | var parts []string |
| 19 | var buf strings.Builder |
| 20 | var inQuote bool |
| 21 | var inBracket bool |
| 22 | for i := 0; i < len(raw); i++ { |
| 23 | ch := raw[i] |
| 24 | switch { |
| 25 | case ch == '"' && (i == 0 || raw[i-1] != '\\'): |
| 26 | inQuote = !inQuote |
| 27 | case ch == '[' && !inQuote: |
| 28 | inBracket = true |
| 29 | buf.WriteByte(ch) |
| 30 | case ch == ']' && !inQuote: |
| 31 | inBracket = false |
| 32 | buf.WriteByte(ch) |
| 33 | case ch == '.' && !inQuote && !inBracket: |
| 34 | if buf.Len() == 0 { |
| 35 | return nil, fmt.Errorf("editorconfig: empty segment in %q", raw) |
| 36 | } |
| 37 | parts = append(parts, buf.String()) |
| 38 | buf.Reset() |
| 39 | default: |
| 40 | if ch == '\\' && i+1 < len(raw) && raw[i+1] == '"' { |
| 41 | buf.WriteByte('"') |
| 42 | i++ |
| 43 | continue |
| 44 | } |
| 45 | buf.WriteByte(ch) |
| 46 | } |
| 47 | } |
| 48 | if inQuote { |
| 49 | return nil, fmt.Errorf("editorconfig: unterminated quote in %q", raw) |
| 50 | } |
| 51 | if buf.Len() > 0 { |
| 52 | parts = append(parts, buf.String()) |
| 53 | } |
| 54 | if len(parts) == 0 { |
| 55 | return nil, fmt.Errorf("editorconfig: empty key path") |
| 56 | } |
| 57 | return parts, nil |
| 58 | } |
| 59 | |
| 60 | // Get walks data using parts and returns the leaf value plus whether it was |
| 61 | // found. Intermediate non-map values cause a not-found result. |
no outgoing calls