Skip to content

Commit dc7878b

Browse files
authored
fix(protoc-gen-elixir-grpc): handle underscores in package names for PascalCase conversion (#37)
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
1 parent 581b755 commit dc7878b

File tree

2 files changed

+129
-55
lines changed

2 files changed

+129
-55
lines changed

cmd/protoc-gen-elixir-grpc/main.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -486,5 +486,14 @@ func toPascalCase(s string) string {
486486
if len(s) == 0 {
487487
return s
488488
}
489-
return strings.ToUpper(s[:1]) + s[1:]
489+
490+
// Split by underscores and capitalize each part
491+
parts := strings.Split(s, "_")
492+
for i, part := range parts {
493+
if len(part) > 0 {
494+
parts[i] = strings.ToUpper(part[:1]) + part[1:]
495+
}
496+
}
497+
498+
return strings.Join(parts, "")
490499
}

cmd/protoc-gen-elixir-grpc/main_test.go

Lines changed: 119 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -494,47 +494,47 @@ end
494494
assert.Equal(t, expected, content)
495495
})
496496

497-
t.Run("with server_module_prefix and handler_module_prefix", func(t *testing.T) {
498-
t.Parallel()
497+
t.Run("with server_module_prefix and handler_module_prefix", func(t *testing.T) {
498+
t.Parallel()
499499

500-
fileDesc := &descriptorpb.FileDescriptorProto{
501-
Name: ptr("invoice/v1/invoice.proto"),
502-
Package: ptr("invoice.v1"),
503-
MessageType: []*descriptorpb.DescriptorProto{
504-
{Name: ptr("CreateInvoiceRequest")},
505-
{Name: ptr("CreateInvoiceResponse")},
506-
},
507-
Service: []*descriptorpb.ServiceDescriptorProto{
508-
{
509-
Name: ptr("InvoiceService"),
510-
Method: []*descriptorpb.MethodDescriptorProto{
511-
{
512-
Name: ptr("CreateInvoice"),
513-
InputType: ptr(".invoice.v1.CreateInvoiceRequest"),
514-
OutputType: ptr(".invoice.v1.CreateInvoiceResponse"),
500+
fileDesc := &descriptorpb.FileDescriptorProto{
501+
Name: ptr("invoice/v1/invoice.proto"),
502+
Package: ptr("invoice.v1"),
503+
MessageType: []*descriptorpb.DescriptorProto{
504+
{Name: ptr("CreateInvoiceRequest")},
505+
{Name: ptr("CreateInvoiceResponse")},
506+
},
507+
Service: []*descriptorpb.ServiceDescriptorProto{
508+
{
509+
Name: ptr("InvoiceService"),
510+
Method: []*descriptorpb.MethodDescriptorProto{
511+
{
512+
Name: ptr("CreateInvoice"),
513+
InputType: ptr(".invoice.v1.CreateInvoiceRequest"),
514+
OutputType: ptr(".invoice.v1.CreateInvoiceResponse"),
515+
},
515516
},
516517
},
517518
},
518-
},
519-
}
519+
}
520520

521-
req := &pluginpb.CodeGeneratorRequest{
522-
FileToGenerate: []string{"invoice/v1/invoice.proto"},
523-
ProtoFile: []*descriptorpb.FileDescriptorProto{fileDesc},
524-
SourceFileDescriptors: []*descriptorpb.FileDescriptorProto{fileDesc},
525-
CompilerVersion: compilerVersion,
526-
Parameter: ptr("server_module_prefix=MyApp.Servers,handler_module_prefix=MyApp.Handlers"),
527-
}
521+
req := &pluginpb.CodeGeneratorRequest{
522+
FileToGenerate: []string{"invoice/v1/invoice.proto"},
523+
ProtoFile: []*descriptorpb.FileDescriptorProto{fileDesc},
524+
SourceFileDescriptors: []*descriptorpb.FileDescriptorProto{fileDesc},
525+
CompilerVersion: compilerVersion,
526+
Parameter: ptr("server_module_prefix=MyApp.Servers,handler_module_prefix=MyApp.Handlers"),
527+
}
528528

529-
rsp := testGenerate(t, req)
530-
assert.Nil(t, rsp.Error)
531-
assert.Equal(t, 1, len(rsp.File))
529+
rsp := testGenerate(t, req)
530+
assert.Nil(t, rsp.Error)
531+
assert.Equal(t, 1, len(rsp.File))
532532

533-
file := rsp.File[0]
534-
assert.Equal(t, "invoice/v1/invoice.server.pb.ex", file.GetName())
533+
file := rsp.File[0]
534+
assert.Equal(t, "invoice/v1/invoice.server.pb.ex", file.GetName())
535535

536-
content := file.GetContent()
537-
expected := `# Code generated by protoc-gen-elixir-grpc. DO NOT EDIT.
536+
content := file.GetContent()
537+
expected := `# Code generated by protoc-gen-elixir-grpc. DO NOT EDIT.
538538
#
539539
# Source: invoice/v1/invoice.proto
540540
@@ -547,32 +547,32 @@ defmodule MyApp.Servers.Invoice.V1.InvoiceService.Server do
547547
as: :handle_message
548548
end
549549
`
550-
assert.Equal(t, expected, content)
551-
})
550+
assert.Equal(t, expected, content)
551+
})
552552

553-
t.Run("with http_transcode and handler_module_prefix", func(t *testing.T) {
554-
t.Parallel()
553+
t.Run("with http_transcode and handler_module_prefix", func(t *testing.T) {
554+
t.Parallel()
555555

556-
fileDesc := &descriptorpb.FileDescriptorProto{
557-
Name: ptr("payment/v1/payment.proto"),
558-
Package: ptr("payment.v1"),
559-
MessageType: []*descriptorpb.DescriptorProto{
560-
{Name: ptr("ProcessRequest")},
561-
{Name: ptr("ProcessResponse")},
562-
},
563-
Service: []*descriptorpb.ServiceDescriptorProto{
564-
{
565-
Name: ptr("PaymentService"),
566-
Method: []*descriptorpb.MethodDescriptorProto{
567-
{
568-
Name: ptr("ProcessPayment"),
569-
InputType: ptr(".payment.v1.ProcessRequest"),
570-
OutputType: ptr(".payment.v1.ProcessResponse"),
556+
fileDesc := &descriptorpb.FileDescriptorProto{
557+
Name: ptr("payment/v1/payment.proto"),
558+
Package: ptr("payment.v1"),
559+
MessageType: []*descriptorpb.DescriptorProto{
560+
{Name: ptr("ProcessRequest")},
561+
{Name: ptr("ProcessResponse")},
562+
},
563+
Service: []*descriptorpb.ServiceDescriptorProto{
564+
{
565+
Name: ptr("PaymentService"),
566+
Method: []*descriptorpb.MethodDescriptorProto{
567+
{
568+
Name: ptr("ProcessPayment"),
569+
InputType: ptr(".payment.v1.ProcessRequest"),
570+
OutputType: ptr(".payment.v1.ProcessResponse"),
571+
},
571572
},
572573
},
573574
},
574-
},
575-
}
575+
}
576576

577577
req := &pluginpb.CodeGeneratorRequest{
578578
FileToGenerate: []string{"payment/v1/payment.proto"},
@@ -830,6 +830,62 @@ end
830830
})
831831
})
832832

833+
t.Run("with underscore in package name", func(t *testing.T) {
834+
t.Parallel()
835+
836+
fileDesc := &descriptorpb.FileDescriptorProto{
837+
Name: ptr("acme/user_profile/v1/user_profile.proto"),
838+
Package: ptr("acme.user_profile.v1"),
839+
MessageType: []*descriptorpb.DescriptorProto{
840+
{Name: ptr("GetUserProfileRequest")},
841+
{Name: ptr("GetUserProfileResponse")},
842+
},
843+
Service: []*descriptorpb.ServiceDescriptorProto{
844+
{
845+
Name: ptr("UserProfileService"),
846+
Method: []*descriptorpb.MethodDescriptorProto{
847+
{
848+
Name: ptr("GetUserProfile"),
849+
InputType: ptr(".acme.user_profile.v1.GetUserProfileRequest"),
850+
OutputType: ptr(".acme.user_profile.v1.GetUserProfileResponse"),
851+
},
852+
},
853+
},
854+
},
855+
}
856+
857+
req := &pluginpb.CodeGeneratorRequest{
858+
FileToGenerate: []string{"acme/user_profile/v1/user_profile.proto"},
859+
ProtoFile: []*descriptorpb.FileDescriptorProto{fileDesc},
860+
SourceFileDescriptors: []*descriptorpb.FileDescriptorProto{fileDesc},
861+
CompilerVersion: compilerVersion,
862+
Parameter: ptr("handler_module_prefix=MyApp.Handlers"),
863+
}
864+
865+
rsp := testGenerate(t, req)
866+
assert.Nil(t, rsp.Error)
867+
assert.Equal(t, 1, len(rsp.File))
868+
869+
file := rsp.File[0]
870+
assert.Equal(t, "acme/user_profile/v1/user_profile.server.pb.ex", file.GetName())
871+
872+
content := file.GetContent()
873+
expected := `# Code generated by protoc-gen-elixir-grpc. DO NOT EDIT.
874+
#
875+
# Source: acme/user_profile/v1/user_profile.proto
876+
877+
defmodule Acme.UserProfile.V1.UserProfileService.Server do
878+
use GRPC.Server,
879+
service: Acme.UserProfile.V1.UserProfileService.Service
880+
881+
defdelegate get_user_profile(request, stream),
882+
to: MyApp.Handlers.Acme.UserProfile.V1.UserProfileService.Server.GetUserProfileHandler,
883+
as: :handle_message
884+
end
885+
`
886+
assert.Equal(t, expected, content)
887+
})
888+
833889
t.Run("no service", func(t *testing.T) {
834890
t.Parallel()
835891

@@ -1111,6 +1167,15 @@ func TestToPascalCase(t *testing.T) {
11111167
{"a", "A"},
11121168
{"ABC", "ABC"},
11131169
{"SayHello", "SayHello"}, // Already PascalCase
1170+
// Underscore handling
1171+
{"team_lookup", "TeamLookup"},
1172+
{"user_profile", "UserProfile"},
1173+
{"get_user_by_id", "GetUserById"},
1174+
{"v1", "V1"},
1175+
{"api_v2", "ApiV2"},
1176+
{"_leading", "Leading"},
1177+
{"trailing_", "Trailing"},
1178+
{"double__underscore", "DoubleUnderscore"},
11141179
}
11151180

11161181
for _, test := range tests {

0 commit comments

Comments
 (0)