Files
ucan/selector/selector.go
2024-08-19 23:16:36 +02:00

111 lines
2.1 KiB
Go

package selector
import (
"fmt"
"strconv"
"strings"
)
// Selector describes a UCAN policy selector, as specified here:
// https://github.com/ucan-wg/delegation/blob/4094d5878b58f5d35055a3b93fccda0b8329ebae/README.md#selectors
type Selector interface {
// Identity flags that this selector is the identity selector.
Identity() bool
// Optional flags that this selector is optional.
Optional() bool
// Field is the name of a field in a struct/map.
Field() string
// Index is an index of a slice.
Index() int
// String returns the selector's string representation.
String() string
}
type selector struct {
str string
identity bool
optional bool
field string
index int
}
func (s selector) Field() string {
return s.field
}
func (s selector) Identity() bool {
return s.identity
}
func (s selector) Index() int {
return s.index
}
func (s selector) Optional() bool {
return s.optional
}
func (s selector) String() string {
return s.str
}
// TODO: probably regex or better parser
func Parse(sel string) (Selector, error) {
s := sel
if s == "." {
return selector{sel, true, false, "", 0}, nil
}
optional := strings.HasSuffix(s, "?")
if optional {
s = s[0 : len(s)-1]
}
dotted := strings.HasPrefix(s, ".")
if dotted {
s = s[1:]
}
// collection values
if s == "[]" {
return nil, fmt.Errorf("unsupported selector: %s", sel)
}
if strings.HasPrefix(s, "[") && strings.HasSuffix(s, "]") {
s = s[1 : len(s)-1]
// explicit field selector
if strings.HasPrefix(s, "\"") && strings.HasSuffix(s, "\"") {
return selector{sel, false, optional, s[1 : len(s)-1], 0}, nil
}
// collection range
if strings.Contains(s, ":") {
return nil, fmt.Errorf("unsupported selector: %s", sel)
}
// index selector
idx, err := strconv.Atoi(s)
if err != nil {
return nil, fmt.Errorf("parsing index selector value: %s", err)
}
return selector{sel, false, optional, "", idx}, nil
}
if !dotted {
return nil, fmt.Errorf("invalid selector: %s", sel)
}
// dotted field selector
return selector{sel, false, optional, s, 0}, nil
}
func MustParse(sel string) Selector {
s, err := Parse(sel)
if err != nil {
panic(err)
}
return s
}