From d6949dbf08142a78821807734524f76c72c747ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Matheson=20Wergeland?= Date: Mon, 21 Mar 2022 20:49:17 +0100 Subject: [PATCH 1/2] Use the canonical camelCase converter for protobuf. Fixes issue #2363. --- internal/casing/LICENSE.md | 2 +- internal/casing/README.md | 8 +++++--- internal/casing/camel.go | 18 ++++++++++++++++++ .../internal/genopenapi/template.go | 16 ++++------------ 4 files changed, 28 insertions(+), 16 deletions(-) diff --git a/internal/casing/LICENSE.md b/internal/casing/LICENSE.md index 0f646931a46..ca708b0f8ab 100644 --- a/internal/casing/LICENSE.md +++ b/internal/casing/LICENSE.md @@ -1,4 +1,4 @@ -Copyright 2010 The Go Authors. All rights reserved. +Copyright 2010, 2019 The Go Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are diff --git a/internal/casing/README.md b/internal/casing/README.md index 88114463aa8..928e0c70d66 100644 --- a/internal/casing/README.md +++ b/internal/casing/README.md @@ -1,5 +1,7 @@ # Case conversion -This package contains a single function, copied from the -`github.com/golang/protobuf/protoc-gen-go/generator` package. That -modules LICENSE is referenced in its entirety in this package. +This package contains two functions: +- `Camel` copied from the `github.com/golang/protobuf/protoc-gen-go/generator` package. +- `JSONCamelCase` copied from the `github.com/protocolbuffers/protobuf-go/internal/strs` package. + +Both these modules are licensed by The Go Authors, as reflected in this package's [LICENSE.md]. diff --git a/internal/casing/camel.go b/internal/casing/camel.go index 8cfef4bf2a6..85e708ea1f4 100644 --- a/internal/casing/camel.go +++ b/internal/casing/camel.go @@ -50,6 +50,24 @@ func Camel(s string) string { return string(t) } +// JSONCamelCase converts a snake_case identifier to a camelCase identifier, +// according to the protobuf JSON specification. +func JSONCamelCase(s string) string { + var b []byte + var wasUnderscore bool + for i := 0; i < len(s); i++ { // proto identifiers are always ASCII + c := s[i] + if c != '_' { + if wasUnderscore && isASCIILower(c) { + c -= 'a' - 'A' // convert to uppercase + } + b = append(b, c) + } + wasUnderscore = c == '_' + } + return string(b) +} + // And now lots of helper functions. // Is c an ASCII lower-case letter? diff --git a/protoc-gen-openapiv2/internal/genopenapi/template.go b/protoc-gen-openapiv2/internal/genopenapi/template.go index df915d34a2b..f16933ed05b 100644 --- a/protoc-gen-openapiv2/internal/genopenapi/template.go +++ b/protoc-gen-openapiv2/internal/genopenapi/template.go @@ -1164,7 +1164,7 @@ func renderServices(services []*descriptor.Service, paths openapiPathsObject, re bodyFieldName = bodyField.Name } // Align pathParams with body field path. - pathParams := subPathParams(bodyFieldName, b.PathParams) + pathParams := subPathParams(bodyField.Name, b.PathParams) var err error schema, err = renderFieldAsDefinition(bodyField.Target, reg, customRefs, pathParams) if err != nil { @@ -2523,7 +2523,7 @@ func updateswaggerObjectFromJSONSchema(s *openapiSchemaObject, j *openapi_option if reg.GetUseJSONNamesForFields() { for i, r := range s.Required { // TODO(oyvindwe): Look up field and use field.GetJsonName()? - s.Required[i] = doCamelCase(r) + s.Required[i] = casing.JSONCamelCase(r) } } s.Enum = j.GetEnum() @@ -2707,7 +2707,7 @@ func lowerCamelCase(fieldName string, fields []*descriptor.Field, msgs []*descri fieldNames := strings.Split(fieldName, ".") fieldNamesWithCamelCase := make([]string, 0) for i := 0; i < len(fieldNames)-1; i++ { - fieldNamesWithCamelCase = append(fieldNamesWithCamelCase, doCamelCase(string(fieldNames[i]))) + fieldNamesWithCamelCase = append(fieldNamesWithCamelCase, casing.JSONCamelCase(string(fieldNames[i]))) } prefix := strings.Join(fieldNamesWithCamelCase, ".") reservedJSONName := getReservedJSONName(fieldName, messageNameToFieldsToJSONName, fieldNameToType) @@ -2715,15 +2715,7 @@ func lowerCamelCase(fieldName string, fields []*descriptor.Field, msgs []*descri return prefix + "." + reservedJSONName } } - return doCamelCase(fieldName) -} - -func doCamelCase(input string) string { - parameterString := casing.Camel(input) - builder := &strings.Builder{} - builder.WriteString(strings.ToLower(string(parameterString[0]))) - builder.WriteString(parameterString[1:]) - return builder.String() + return casing.JSONCamelCase(fieldName) } func getReservedJSONName(fieldName string, messageNameToFieldsToJSONName map[string]map[string]string, fieldNameToType map[string]string) string { From 3560f0386d480872255e5a7b24135715f86940b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Matheson=20Wergeland?= Date: Mon, 21 Mar 2022 21:54:03 +0100 Subject: [PATCH 2/2] Revert change that should go in separate PR --- protoc-gen-openapiv2/internal/genopenapi/template.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protoc-gen-openapiv2/internal/genopenapi/template.go b/protoc-gen-openapiv2/internal/genopenapi/template.go index f16933ed05b..6af43c04e81 100644 --- a/protoc-gen-openapiv2/internal/genopenapi/template.go +++ b/protoc-gen-openapiv2/internal/genopenapi/template.go @@ -1164,7 +1164,7 @@ func renderServices(services []*descriptor.Service, paths openapiPathsObject, re bodyFieldName = bodyField.Name } // Align pathParams with body field path. - pathParams := subPathParams(bodyField.Name, b.PathParams) + pathParams := subPathParams(bodyFieldName, b.PathParams) var err error schema, err = renderFieldAsDefinition(bodyField.Target, reg, customRefs, pathParams) if err != nil {