Move how the template language is written into internal/grammar

This commit is contained in:
2026-10-05 12:11:36 +02:00
committed by Lillem4n
parent 41292f9d89
commit c2f2e86735
21 changed files with 903 additions and 853 deletions
+41
View File
@@ -0,0 +1,41 @@
package grammar
import (
"fmt"
"strings"
)
// A reference names a node by path rather than as a sibling field: {/a.b} from the
// data root, {.a} from the folder this file sits in, {..a} from the folder above.
func IsRef(name string) bool { return strings.HasPrefix(name, ".") || strings.HasPrefix(name, "/") }
// RefShape splits a reference into its sigil and the dotted path after it.
func RefShape(name string) (sigil, rest string, err error) {
switch {
case strings.HasPrefix(name, "/"):
sigil, rest = "/", name[1:]
case strings.HasPrefix(name, ".."):
sigil, rest = "..", name[2:]
default:
sigil, rest = ".", name[1:]
}
if rest == "" {
return "", "", fmt.Errorf("reference has no path")
}
if strings.HasPrefix(rest, "/") {
return "", "", fmt.Errorf("the path after %s starts at a name, not a /; write {%s%s}", sigil, sigil, rest[1:])
}
if strings.HasPrefix(rest, ".") {
return "", "", fmt.Errorf("a reference starts with / (the root), . (this folder) or .. (the folder above)")
}
segs, err := SplitPath(rest)
if err != nil {
return "", "", err
}
for _, seg := range segs {
if seg == "" {
return "", "", fmt.Errorf("path has an empty segment")
}
}
return sigil, rest, nil
}