Browse Source

types/model: allow _ as starter character in Name parts (#3991)

Blake Mizerany 1 year ago
parent
commit
114c932a8e
2 changed files with 11 additions and 10 deletions
  1. 9 9
      types/model/name.go
  2. 2 1
      types/model/name_test.go

+ 9 - 9
types/model/name.go

@@ -109,19 +109,19 @@ type Name struct {
 //		  { model }
 //		  { model }
 //		  "@" { digest }
 //		  "@" { digest }
 //	  host:
 //	  host:
-//	      pattern: alphanum { alphanum | "-" | "_" | "." | ":" }*
+//	      pattern: { alphanum | "_" } { alphanum | "-" | "_" | "." | ":" }*
 //	      length:  [1, 350]
 //	      length:  [1, 350]
 //	  namespace:
 //	  namespace:
-//	      pattern: alphanum { alphanum | "-" | "_" }*
+//	      pattern: { alphanum | "_" } { alphanum | "-" | "_" }*
 //	      length:  [1, 80]
 //	      length:  [1, 80]
 //	  model:
 //	  model:
-//	      pattern: alphanum { alphanum | "-" | "_" | "." }*
+//	      pattern: { alphanum | "_" } { alphanum | "-" | "_" | "." }*
 //	      length:  [1, 80]
 //	      length:  [1, 80]
 //	  tag:
 //	  tag:
-//	      pattern: alphanum { alphanum | "-" | "_" | "." }*
+//	      pattern: { alphanum | "_" } { alphanum | "-" | "_" | "." }*
 //	      length:  [1, 80]
 //	      length:  [1, 80]
 //	  digest:
 //	  digest:
-//	      pattern: alphanum { alphanum | "-" | ":" }*
+//	      pattern: { alphanum | "_" } { alphanum | "-" | ":" }*
 //	      length:  [1, 80]
 //	      length:  [1, 80]
 //
 //
 // Most users should use [ParseName] instead, unless need to support
 // Most users should use [ParseName] instead, unless need to support
@@ -264,7 +264,7 @@ func isValidPart(kind partKind, s string) bool {
 	}
 	}
 	for i := range s {
 	for i := range s {
 		if i == 0 {
 		if i == 0 {
-			if !isAlphanumeric(s[i]) {
+			if !isAlphanumericOrUnderscore(s[i]) {
 				return false
 				return false
 			}
 			}
 			continue
 			continue
@@ -280,7 +280,7 @@ func isValidPart(kind partKind, s string) bool {
 				return false
 				return false
 			}
 			}
 		default:
 		default:
-			if !isAlphanumeric(s[i]) {
+			if !isAlphanumericOrUnderscore(s[i]) {
 				return false
 				return false
 			}
 			}
 		}
 		}
@@ -288,8 +288,8 @@ func isValidPart(kind partKind, s string) bool {
 	return true
 	return true
 }
 }
 
 
-func isAlphanumeric(c byte) bool {
-	return c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z' || c >= '0' && c <= '9'
+func isAlphanumericOrUnderscore(c byte) bool {
+	return c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z' || c >= '0' && c <= '9' || c == '_'
 }
 }
 
 
 func cutLast(s, sep string) (before, after string, ok bool) {
 func cutLast(s, sep string) (before, after string, ok bool) {

+ 2 - 1
types/model/name_test.go

@@ -103,6 +103,8 @@ func TestParseNameParts(t *testing.T) {
 var testCases = map[string]bool{ // name -> valid
 var testCases = map[string]bool{ // name -> valid
 	"": false,
 	"": false,
 
 
+	"_why/_the/_lucky:_stiff": true,
+
 	// minimal
 	// minimal
 	"h/n/m:t@d": true,
 	"h/n/m:t@d": true,
 
 
@@ -167,7 +169,6 @@ func TestNameIsValid(t *testing.T) {
 	var numStringTests int
 	var numStringTests int
 	for s, want := range testCases {
 	for s, want := range testCases {
 		n := ParseNameBare(s)
 		n := ParseNameBare(s)
-		t.Logf("n: %#v", n)
 		got := n.IsValid()
 		got := n.IsValid()
 		if got != want {
 		if got != want {
 			t.Errorf("parseName(%q).IsValid() = %v; want %v", s, got, want)
 			t.Errorf("parseName(%q).IsValid() = %v; want %v", s, got, want)