@@ -54,33 +54,89 @@ const (
5454 packagePrefixFlag = "package_prefix"
5555 handlerModulePrefixFlag = "handler_module_prefix"
5656 httpTranscodeFlag = "http_transcode"
57+ codecsFlag = "codecs"
5758
58- usage = "\n \n Flags:\n -h, --help\t Print this help and exit.\n --version\t Print the version and exit.\n --handler_module_prefix\t Custom Elixir module prefix for handler modules instead of protobuf package.\n --http_transcode\t Enable HTTP transcoding support (adds http_transcode: true to use GRPC.Server)."
59+ usage = "\n \n Flags:\n -h, --help\t Print this help and exit.\n --version\t Print the version and exit.\n --handler_module_prefix\t Custom Elixir module prefix for handler modules instead of protobuf package.\n --http_transcode\t Enable HTTP transcoding support (adds http_transcode: true to use GRPC.Server).\n --codecs \t Comma-separated list of codec modules (e.g., 'GRPC.Codec.Proto,GRPC.Codec.WebText,GRPC.Codec.JSON'). "
5960)
6061
6162func parsePluginParameters (paramStr string , flagSet * flag.FlagSet ) error {
6263 if paramStr == "" {
6364 return nil
6465 }
6566
66- params := strings .Split (paramStr , "," )
67- for _ , param := range params {
68- param = strings .TrimSpace (param )
69- if param == "" {
67+ // Parse key=value pairs, handling values that may contain commas
68+ params := parseKeyValuePairs (paramStr )
69+ for key , value := range params {
70+ if err := flagSet .Set (key , value ); err != nil {
71+ return err
72+ }
73+ }
74+
75+ return nil
76+ }
77+
78+ // parseKeyValuePairs parses a comma-separated list of key=value pairs.
79+ // It handles the special case where a value may contain commas (e.g., codecs=A,B,C).
80+ // The parser works by splitting on commas, then checking if each segment is a valid key=value pair.
81+ // If not, it's assumed to be a continuation of the previous value.
82+ func parseKeyValuePairs (paramStr string ) map [string ]string {
83+ result := make (map [string ]string )
84+
85+ segments := strings .Split (paramStr , "," )
86+ var currentKey string
87+ var currentValue strings.Builder
88+
89+ for i , segment := range segments {
90+ segment = strings .TrimSpace (segment )
91+ if segment == "" {
7092 continue
7193 }
7294
73- parts := strings .SplitN (param , "=" , 2 )
74- if len (parts ) != 2 {
75- return fmt .Errorf ("invalid parameter format: %q, expected key=value" , param )
95+ // Check if this segment contains an '=' sign
96+ if idx := strings .Index (segment , "=" ); idx > 0 {
97+ // This is a new key=value pair
98+ // Save the previous key-value if exists
99+ if currentKey != "" {
100+ result [currentKey ] = currentValue .String ()
101+ }
102+
103+ // Start new key-value
104+ currentKey = strings .TrimSpace (segment [:idx ])
105+ valueStart := strings .TrimSpace (segment [idx + 1 :])
106+ currentValue .Reset ()
107+ currentValue .WriteString (valueStart )
108+ } else {
109+ // This is a continuation of the current value
110+ if currentKey != "" {
111+ currentValue .WriteString ("," )
112+ currentValue .WriteString (segment )
113+ }
76114 }
77115
78- if err := flagSet .Set (parts [0 ], parts [1 ]); err != nil {
79- return err
116+ // If this is the last segment, save the current key-value
117+ if i == len (segments )- 1 && currentKey != "" {
118+ result [currentKey ] = currentValue .String ()
80119 }
81120 }
82121
83- return nil
122+ return result
123+ }
124+
125+ func parseCodecs (codecsStr string ) []string {
126+ if codecsStr == "" {
127+ return nil
128+ }
129+
130+ codecs := strings .Split (codecsStr , "," )
131+ var result []string
132+ for _ , codec := range codecs {
133+ codec = strings .TrimSpace (codec )
134+ if codec != "" {
135+ result = append (result , codec )
136+ }
137+ }
138+
139+ return result
84140}
85141
86142func main () {
@@ -117,6 +173,11 @@ func main() {
117173 false ,
118174 "Enable HTTP transcoding support (adds http_transcode: true to use GRPC.Server)." ,
119175 )
176+ codecs := flagSet .String (
177+ codecsFlag ,
178+ "" ,
179+ "Comma-separated list of codec modules (e.g., 'GRPC.Codec.Proto,GRPC.Codec.WebText,GRPC.Codec.JSON')." ,
180+ )
120181
121182 input , err := io .ReadAll (os .Stdin )
122183 if err != nil {
@@ -152,6 +213,8 @@ func main() {
152213 SupportedFeatures : proto .Uint64 (uint64 (pluginpb .CodeGeneratorResponse_FEATURE_PROTO3_OPTIONAL )),
153214 }
154215
216+ codecsList := parseCodecs (* codecs )
217+
155218 for _ , fileName := range req .FileToGenerate {
156219 var protoFile * descriptorpb.FileDescriptorProto
157220 for _ , file := range req .ProtoFile {
@@ -168,7 +231,7 @@ func main() {
168231 continue
169232 }
170233
171- generateElixirFile (resp , protoFile , * packagePrefix , * handlerModulePrefix , * httpTranscode )
234+ generateElixirFile (resp , protoFile , * packagePrefix , * handlerModulePrefix , * httpTranscode , codecsList )
172235 }
173236
174237 output , err := proto .Marshal (resp )
@@ -183,7 +246,7 @@ func main() {
183246 }
184247}
185248
186- func generateElixirFile (resp * pluginpb.CodeGeneratorResponse , file * descriptorpb.FileDescriptorProto , packagePrefix , handlerModulePrefix string , httpTranscode bool ) {
249+ func generateElixirFile (resp * pluginpb.CodeGeneratorResponse , file * descriptorpb.FileDescriptorProto , packagePrefix , handlerModulePrefix string , httpTranscode bool , codecs [] string ) {
187250 if len (file .Service ) == 0 {
188251 return
189252 }
@@ -197,7 +260,7 @@ func generateElixirFile(resp *pluginpb.CodeGeneratorResponse, file *descriptorpb
197260 content .WriteString ("\n " )
198261
199262 for _ , service := range file .Service {
200- generateServiceModule (& content , file , service , handlerModulePrefix , httpTranscode )
263+ generateServiceModule (& content , file , service , handlerModulePrefix , httpTranscode , codecs )
201264 content .WriteString ("\n " )
202265 }
203266
@@ -207,14 +270,25 @@ func generateElixirFile(resp *pluginpb.CodeGeneratorResponse, file *descriptorpb
207270 })
208271}
209272
210- func generateServiceModule (content * strings.Builder , file * descriptorpb.FileDescriptorProto , service * descriptorpb.ServiceDescriptorProto , handlerModulePrefix string , httpTranscode bool ) {
273+ func generateServiceModule (content * strings.Builder , file * descriptorpb.FileDescriptorProto , service * descriptorpb.ServiceDescriptorProto , handlerModulePrefix string , httpTranscode bool , codecs [] string ) {
211274 serverModuleName := generateServerModuleName (file , service )
212275 serviceModuleName := generateServiceModuleName (file , service )
213276
214277 content .WriteString ("defmodule " + serverModuleName + " do\n " )
215- content .WriteString (" use GRPC.Server, service: " + serviceModuleName )
278+ content .WriteString (" use GRPC.Server,\n " )
279+ content .WriteString (" service: " + serviceModuleName )
216280 if httpTranscode {
217- content .WriteString (", http_transcode: true" )
281+ content .WriteString (",\n http_transcode: true" )
282+ }
283+ if len (codecs ) > 0 {
284+ content .WriteString (",\n codecs: [" )
285+ for i , codec := range codecs {
286+ if i > 0 {
287+ content .WriteString (", " )
288+ }
289+ content .WriteString (codec )
290+ }
291+ content .WriteString ("]" )
218292 }
219293 content .WriteString ("\n \n " )
220294
0 commit comments