Repository: ogen-go/ogen
Pull request #605 (2022-10-06 10:48:17)

refactor: use `Cut` instead of `SplitN` and `Index`


Patch:
diff --git a/gen/generics.go b/gen/generics.go
index 9410c07e..ce2be5ee 100644
--- a/gen/generics.go
+++ b/gen/generics.go
@@ -1,11 +1,10 @@
 package gen
 
 import (
-	"strings"
-
 	"github.com/go-faster/errors"
 
 	"github.com/ogen-go/ogen/gen/ir"
+	"github.com/ogen-go/ogen/internal/naming"
 )
 
 func checkStructRecursions(ctx *genctx, s *ir.Type) error {
@@ -119,9 +118,6 @@ func boxType(t *ir.Type, v ir.GenericVariant) (*ir.Type, error) {
 }
 
 func genericPostfix(t *ir.Type) (string, error) {
-	name := t.NamePostfix()
-	if idx := strings.Index(name, "."); idx > 0 {
-		name = name[idx+1:]
-	}
+	name := naming.AfterDot(t.NamePostfix())
 	return pascal(name)
 }
diff --git a/gen/ir/template_helpers.go b/gen/ir/template_helpers.go
index 58d16076..8563b00d 100644
--- a/gen/ir/template_helpers.go
+++ b/gen/ir/template_helpers.go
@@ -2,20 +2,11 @@ package ir
 
 import (
 	"fmt"
-	"strings"
 
 	"github.com/ogen-go/ogen/internal/naming"
 	"github.com/ogen-go/ogen/jsonschema"
 )
 
-func afterDot(v string) string {
-	idx := strings.Index(v, ".")
-	if idx > 0 {
-		return v[idx+1:]
-	}
-	return v
-}
-
 func (t *Type) EncodeFn() string {
 	if t.Is(KindArray) && t.Item.EncodeFn() != "" {
 		return t.Item.EncodeFn() + "Array"
@@ -29,7 +20,7 @@ func (t *Type) EncodeFn() string {
 		String, Bool:
 		return naming.Capitalize(t.Primitive.String())
 	case UUID, Time, IP, Duration, URL:
-		return afterDot(t.Primitive.String())
+		return naming.AfterDot(t.Primitive.String())
 	default:
 		return ""
 	}
diff --git a/gen/options.go b/gen/options.go
index 6c656c61..fec58e73 100644
--- a/gen/options.go
+++ b/gen/options.go
@@ -85,11 +85,11 @@ func (m *ContentTypeAliases) Set(value string) error {
 	if *m == nil {
 		*m = ContentTypeAliases{}
 	}
-	split := strings.SplitN(value, "=", 2)
-	if len(split) != 2 {
+	before, after, ok := strings.Cut(value, "=")
+	if !ok {
 		return errors.Errorf("invalid mapping %q", value)
 	}
-	(*m)[split[0]] = ir.Encoding(split[1])
+	(*m)[before] = ir.Encoding(after)
 	return nil
 }
 
diff --git a/internal/naming/after_dot.go b/internal/naming/after_dot.go
new file mode 100644
index 00000000..2b514121
--- /dev/null
+++ b/internal/naming/after_dot.go
@@ -0,0 +1,13 @@
+package naming
+
+import "strings"
+
+// AfterDot returns the part of the string after the first dot.
+//
+// If there is no dot in the string or dot is the first character, the whole string is returned.
+func AfterDot(s string) string {
+	if before, after, ok := strings.Cut(s, "."); ok && before != "" {
+		return after
+	}
+	return s
+}
diff --git a/internal/naming/capitalize.go b/internal/naming/capitalize.go
index c4a3c8e4..33734f20 100644
--- a/internal/naming/capitalize.go
+++ b/internal/naming/capitalize.go
@@ -6,7 +6,12 @@ import (
 )
 
 // Capitalize converts first character to upper.
+//
+// If the string is invalid UTF-8 or empty, it is returned as is.
 func Capitalize(s string) string {
 	r, size := utf8.DecodeRuneInString(s)
+	if r == utf8.RuneError {
+		return s
+	}
 	return string(unicode.ToUpper(r)) + s[size:]
 }


Test patch:
diff --git a/internal/naming/after_dot_test.go b/internal/naming/after_dot_test.go
new file mode 100644
index 00000000..500f75c6
--- /dev/null
+++ b/internal/naming/after_dot_test.go
@@ -0,0 +1,30 @@
+package naming
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/stretchr/testify/require"
+)
+
+func TestAfterDot(t *testing.T) {
+	tests := []struct {
+		input string
+		want  string
+	}{
+		// Dot is the second character: return the part after the dot.
+		{"a.b", "b"},
+		// No dot: return the whole string.
+		{"", ""},
+		{"a", "a"},
+		// Dot is the first character: return the whole string.
+		{".", "."},
+		{".ab", ".ab"},
+	}
+	for i, tt := range tests {
+		tt := tt
+		t.Run(fmt.Sprintf("Test%d", i+1), func(t *testing.T) {
+			require.Equal(t, tt.want, AfterDot(tt.input))
+		})
+	}
+}
diff --git a/internal/naming/capitalize_test.go b/internal/naming/capitalize_test.go
new file mode 100644
index 00000000..e890a236
--- /dev/null
+++ b/internal/naming/capitalize_test.go
@@ -0,0 +1,27 @@
+package naming
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/stretchr/testify/require"
+)
+
+func TestCapitalize(t *testing.T) {
+	tests := []struct {
+		input string
+		want  string
+	}{
+		{"", ""},
+		{"\x87", "\x87"},
+		{"int8", "Int8"},
+		{"Int8", "Int8"},
+		{"хлеб", "Хлеб"},
+	}
+	for i, tt := range tests {
+		tt := tt
+		t.Run(fmt.Sprintf("Test%d", i+1), func(t *testing.T) {
+			require.Equal(t, tt.want, Capitalize(tt.input))
+		})
+	}
+}