fork of indigo with slightly nicer lexgen
at main 2.1 kB view raw
1package syntax 2 3import ( 4 "errors" 5 "regexp" 6 "strings" 7) 8 9var nsidRegex = regexp.MustCompile(`^[a-zA-Z]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(\.[a-zA-Z]([a-zA-Z0-9]{0,62})?)$`) 10 11// String type which represents a syntaxtually valid Namespace Identifier (NSID), as would pass Lexicon syntax validation. 12// 13// Always use [ParseNSID] instead of wrapping strings directly, especially when working with input. 14// 15// Syntax specification: https://atproto.com/specs/nsid 16type NSID string 17 18func ParseNSID(raw string) (NSID, error) { 19 if raw == "" { 20 return "", errors.New("expected NSID, got empty string") 21 } 22 if len(raw) > 317 { 23 return "", errors.New("NSID is too long (317 chars max)") 24 } 25 if !nsidRegex.MatchString(raw) { 26 return "", errors.New("NSID syntax didn't validate via regex") 27 } 28 return NSID(raw), nil 29} 30 31// Authority domain name, in regular DNS order, not reversed order, normalized to lower-case. 32func (n NSID) Authority() string { 33 parts := strings.Split(string(n), ".") 34 if len(parts) < 2 { 35 // something has gone wrong (would not validate); return empty string instead 36 return "" 37 } 38 // NSID must have at least two parts, verified by ParseNSID 39 parts = parts[:len(parts)-1] 40 // reverse 41 for i, j := 0, len(parts)-1; i < j; i, j = i+1, j-1 { 42 parts[i], parts[j] = parts[j], parts[i] 43 } 44 return strings.ToLower(strings.Join(parts, ".")) 45} 46 47func (n NSID) Name() string { 48 parts := strings.Split(string(n), ".") 49 return parts[len(parts)-1] 50} 51 52func (n NSID) String() string { 53 return string(n) 54} 55 56func (n NSID) Normalize() NSID { 57 parts := strings.Split(string(n), ".") 58 if len(parts) < 2 { 59 // something has gone wrong (would not validate); just return the whole identifier 60 return n 61 } 62 name := parts[len(parts)-1] 63 prefix := strings.ToLower(strings.Join(parts[:len(parts)-1], ".")) 64 return NSID(prefix + "." + name) 65} 66 67func (n NSID) MarshalText() ([]byte, error) { 68 return []byte(n.String()), nil 69} 70 71func (n *NSID) UnmarshalText(text []byte) error { 72 nsid, err := ParseNSID(string(text)) 73 if err != nil { 74 return err 75 } 76 *n = nsid 77 return nil 78}