code.oscarkilo.com/okg

Hash:
a34149f26d2366df0daafd8539ff51ac7833ee16
Author:
Igor Naverniouk <[email protected]>
Date:
Fri Jun 5 13:12:40 2026 -0400
Message:
okg/who: add username helpers (mirrors //clients/who) Pure-function helpers + regex constants for //who usernames, copied byte-for-byte from //clients/who/who.go: - UsernameRegex, FullUsernameRegex (consts) - IsValidUsername, IsSubUsername, ParentUsername (funcs) Prerequisite for letting //clients/who alias them back to here. Backends that import //clients/who keep their imports unchanged; a follow-up commit turns //clients/who's local definitions into aliases pointing at this package. Tests cover the boundary cases (length 32 vs 33, sub-usernames with two dots, leading/trailing dots, uppercase rejection).
diff --git a/who/username.go b/who/username.go
new file mode 100644
index 0000000..9e6decc
--- /dev/null
+++ b/who/username.go
@@ -0,0 +1,46 @@
+package who
+
+import "regexp"
+import "strings"
+
+// UsernameRegex matches a primary //who username: starts with a
+// lowercase letter, then up to 31 more lowercase letters,
+// digits, hyphens, or underscores.
+const UsernameRegex = `[a-z][-a-z0-9_]{0,31}`
+
+// usernamePattern is the compiled, anchored form of
+// UsernameRegex, used by IsValidUsername.
+var usernamePattern = regexp.MustCompile(
+ `^` + UsernameRegex + `$`)
+
+// IsValidUsername returns true if the username matches
+// UsernameRegex.
+func IsValidUsername(username string) bool {
+ return usernamePattern.MatchString(username)
+}
+
+// FullUsernameRegex matches both regular usernames and
+// sub-usernames (parent.child).
+const FullUsernameRegex = UsernameRegex +
+ `(\.` + UsernameRegex + `)?`
+
+// IsSubUsername returns true if username is a valid sub-username
+// (contains exactly one dot, both parts valid).
+func IsSubUsername(username string) bool {
+ dot := strings.IndexByte(username, '.')
+ if dot < 0 {
+ return false
+ }
+ return IsValidUsername(username[:dot]) &&
+ IsValidUsername(username[dot+1:])
+}
+
+// ParentUsername returns the parent portion of a sub-username,
+// or "" if not a sub-username.
+func ParentUsername(username string) string {
+ dot := strings.IndexByte(username, '.')
+ if dot < 0 {
+ return ""
+ }
+ return username[:dot]
+}
diff --git a/who/username_test.go b/who/username_test.go
new file mode 100644
index 0000000..d4e4766
--- /dev/null
+++ b/who/username_test.go
@@ -0,0 +1,51 @@
+package who
+
+import "testing"
+
+func TestIsValidUsername(t *testing.T) {
+ check := func(in string, want bool) {
+ t.Helper()
+ if got := IsValidUsername(in); got != want {
+ t.Errorf("IsValidUsername(%q): got %v, want %v",
+ in, got, want)
+ }
+ }
+ check("alice", true)
+ check("a", true)
+ check("a-b", true)
+ check("a_b", true)
+ check("a123", true)
+ check("", false)
+ check("Alice", false) // uppercase
+ check("1alice", false) // starts with digit
+ check("alice.bob", false) // dot (sub-username)
+ check("alice@bob", false) // disallowed char
+ check("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", false) // 33 chars
+}
+
+func TestIsSubUsername(t *testing.T) {
+ check := func(in string, want bool) {
+ t.Helper()
+ if got := IsSubUsername(in); got != want {
+ t.Errorf("IsSubUsername(%q): got %v, want %v",
+ in, got, want)
+ }
+ }
+ check("alice.bob", true)
+ check("alice", false)
+ check("alice.bob.charlie", false) // two dots
+ check(".bob", false)
+ check("alice.", false)
+}
+
+func TestParentUsername(t *testing.T) {
+ check := func(in, want string) {
+ t.Helper()
+ if got := ParentUsername(in); got != want {
+ t.Errorf("ParentUsername(%q): got %q, want %q",
+ in, got, want)
+ }
+ }
+ check("alice.bob", "alice")
+ check("alice", "")
+}
/dev/null
b/who/username.go
1
package who
2
3
import "regexp"
4
import "strings"
5
6
// UsernameRegex matches a primary //who username: starts with a
7
// lowercase letter, then up to 31 more lowercase letters,
8
// digits, hyphens, or underscores.
9
const UsernameRegex = `[a-z][-a-z0-9_]{0,31}`
10
11
// usernamePattern is the compiled, anchored form of
12
// UsernameRegex, used by IsValidUsername.
13
var usernamePattern = regexp.MustCompile(
14
`^` + UsernameRegex + `$`)
15
16
// IsValidUsername returns true if the username matches
17
// UsernameRegex.
18
func IsValidUsername(username string) bool {
19
return usernamePattern.MatchString(username)
20
}
21
22
// FullUsernameRegex matches both regular usernames and
23
// sub-usernames (parent.child).
24
const FullUsernameRegex = UsernameRegex +
25
`(\.` + UsernameRegex + `)?`
26
27
// IsSubUsername returns true if username is a valid sub-username
28
// (contains exactly one dot, both parts valid).
29
func IsSubUsername(username string) bool {
30
dot := strings.IndexByte(username, '.')
31
if dot < 0 {
32
return false
33
}
34
return IsValidUsername(username[:dot]) &&
35
IsValidUsername(username[dot+1:])
36
}
37
38
// ParentUsername returns the parent portion of a sub-username,
39
// or "" if not a sub-username.
40
func ParentUsername(username string) string {
41
dot := strings.IndexByte(username, '.')
42
if dot < 0 {
43
return ""
44
}
45
return username[:dot]
46
}
/dev/null
b/who/username_test.go
1
package who
2
3
import "testing"
4
5
func TestIsValidUsername(t *testing.T) {
6
check := func(in string, want bool) {
7
t.Helper()
8
if got := IsValidUsername(in); got != want {
9
t.Errorf("IsValidUsername(%q): got %v, want %v",
10
in, got, want)
11
}
12
}
13
check("alice", true)
14
check("a", true)
15
check("a-b", true)
16
check("a_b", true)
17
check("a123", true)
18
check("", false)
19
check("Alice", false) // uppercase
20
check("1alice", false) // starts with digit
21
check("alice.bob", false) // dot (sub-username)
22
check("alice@bob", false) // disallowed char
23
check("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", false) // 33 chars
24
}
25
26
func TestIsSubUsername(t *testing.T) {
27
check := func(in string, want bool) {
28
t.Helper()
29
if got := IsSubUsername(in); got != want {
30
t.Errorf("IsSubUsername(%q): got %v, want %v",
31
in, got, want)
32
}
33
}
34
check("alice.bob", true)
35
check("alice", false)
36
check("alice.bob.charlie", false) // two dots
37
check(".bob", false)
38
check("alice.", false)
39
}
40
41
func TestParentUsername(t *testing.T) {
42
check := func(in, want string) {
43
t.Helper()
44
if got := ParentUsername(in); got != want {
45
t.Errorf("ParentUsername(%q): got %q, want %q",
46
in, got, want)
47
}
48
}
49
check("alice.bob", "alice")
50
check("alice", "")
51
}