Skip to content

Commit c6f4883

Browse files
authored
fix: camelcase and pascalcase transformation logic (#35)
## Description In sprig, `camelCase` return a `PascalCase` and don't respect the separation logic between both functions. ## Changes - Introduce a `toPascalCase` function to transform a string to a `PascalCase` - Fix the behivour of `toCamelCase` function to transform a string to a `camelCase` ## Fixes Masterminds/sprig#328 ## Checklist - [ ] I have read the **CONTRIBUTING.md** document. - [ ] My code follows the code style of this project. - [ ] I have added tests to cover my changes. - [ ] All new and existing tests passed. - [ ] I have updated the documentation accordingly. - [ ] This change requires a change to the documentation on the website. ## Additional Information This edit are related to Masterminds/sprig#328 Backport ticket from @ghostsquad
1 parent 6c2f8f0 commit c6f4883

File tree

2 files changed

+33
-19
lines changed

2 files changed

+33
-19
lines changed

strings_functions.go

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,17 @@ import (
4343
// }
4444
// Use `style` to transform "ExampleText" to "example_text"
4545
type caseStyle struct {
46-
Separator rune // Character that separates words.
47-
CapitalizeNext bool // Whether to capitalize the first character of each word.
48-
ForceLowercase bool // Whether to force all characters to lowercase.
49-
ForceUppercase bool // Whether to force all characters to uppercase.
46+
Separator rune // Character that separates words.
47+
CapitalizeFirst bool // Whether to capitalize the first character of the string.
48+
CapitalizeNext bool // Whether to capitalize the first character of each word.
49+
ForceLowercase bool // Whether to force all characters to lowercase.
50+
ForceUppercase bool // Whether to force all characters to uppercase.
5051
}
5152

5253
var (
53-
camelCaseStyle = caseStyle{Separator: -1, CapitalizeNext: true, ForceLowercase: true}
54+
camelCaseStyle = caseStyle{Separator: -1, CapitalizeNext: true, CapitalizeFirst: false, ForceLowercase: true}
5455
kebabCaseStyle = caseStyle{Separator: '-', ForceLowercase: true}
55-
pascalCaseStyle = caseStyle{Separator: -1, CapitalizeNext: true}
56+
pascalCaseStyle = caseStyle{Separator: -1, CapitalizeFirst: true, CapitalizeNext: true}
5657
snakeCaseStyle = caseStyle{Separator: '_', ForceLowercase: true}
5758
dotCaseStyle = caseStyle{Separator: '.', ForceLowercase: true}
5859
pathCaseStyle = caseStyle{Separator: '/', ForceLowercase: true}
@@ -702,8 +703,13 @@ func (fh *FunctionHandler) Squote(elements ...any) string {
702703
func (fh *FunctionHandler) transformString(style caseStyle, str string) string {
703704
var result strings.Builder
704705
result.Grow(len(str) + 10) // Allocate a bit more for potential separators
705-
capitalizeNext := style.CapitalizeNext
706-
var lastRune, nextRune rune = 0, 0
706+
707+
var capitalizeNext = style.CapitalizeNext
708+
var lastRune, lastLetter, nextRune rune = 0, 0, 0
709+
710+
if !style.CapitalizeFirst {
711+
capitalizeNext = false
712+
}
707713

708714
for i, r := range str {
709715
if i+1 < len(str) {
@@ -714,7 +720,10 @@ func (fh *FunctionHandler) transformString(style caseStyle, str string) string {
714720
if style.Separator != -1 && (lastRune != style.Separator) {
715721
result.WriteRune(style.Separator)
716722
}
717-
capitalizeNext = true
723+
if lastLetter != 0 {
724+
capitalizeNext = true
725+
}
726+
718727
lastRune = style.Separator
719728
continue
720729
}
@@ -739,7 +748,11 @@ func (fh *FunctionHandler) transformString(style caseStyle, str string) string {
739748
} else {
740749
result.WriteRune(r)
741750
}
751+
742752
lastRune = r // Update lastRune to the current rune
753+
if unicode.IsLetter(r) {
754+
lastLetter = r
755+
}
743756
}
744757

745758
return result.String()

strings_functions_test.go

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -279,16 +279,17 @@ func TestSquote(t *testing.T) {
279279
func TestToCamelCase(t *testing.T) {
280280
var tests = testCases{
281281
{"TestEmpty", `{{ "" | toCamelCase }}`, "", nil},
282-
{"TestCamelCase", `{{ "foo bar" | toCamelCase }}`, "FooBar", nil},
283-
{"TestCamelCaseWithSpace", `{{ "foo bar" | toCamelCase }}`, "FooBar", nil},
284-
{"TestCamelCaseWithUnderscore", `{{ "foo_bar" | toCamelCase }}`, "FooBar", nil},
285-
{"TestCamelCaseWithHyphen", `{{ "foo-bar" | toCamelCase }}`, "FooBar", nil},
286-
{"TestCamelCaseWithMixed", `{{ "foo-bar_baz" | toCamelCase }}`, "FooBarBaz", nil},
287-
{"", `{{ toCamelCase "_complex__case_" }}`, "ComplexCase", nil},
288-
{"", `{{ toCamelCase "_camel_case" }}`, "CamelCase", nil},
289-
{"", `{{ toCamelCase "http_server" }}`, "HttpServer", nil},
290-
{"", `{{ toCamelCase "no_https" }}`, "NoHttps", nil},
291-
{"", `{{ toCamelCase "all" }}`, "All", nil},
282+
{"TestCamelCase", `{{ "foo bar" | toCamelCase }}`, "fooBar", nil},
283+
{"TestCamelCaseWithUpperCase", `{{ "FoO bar" | toCamelCase }}`, "fooBar", nil},
284+
{"TestCamelCaseWithSpace", `{{ "foo bar" | toCamelCase }}`, "fooBar", nil},
285+
{"TestCamelCaseWithUnderscore", `{{ "foo_bar" | toCamelCase }}`, "fooBar", nil},
286+
{"TestCamelCaseWithHyphen", `{{ "foo-bar" | toCamelCase }}`, "fooBar", nil},
287+
{"TestCamelCaseWithMixed", `{{ "foo-bar_baz" | toCamelCase }}`, "fooBarBaz", nil},
288+
{"", `{{ toCamelCase "___complex__case_" }}`, "complexCase", nil},
289+
{"", `{{ toCamelCase "_camel_case" }}`, "camelCase", nil},
290+
{"", `{{ toCamelCase "http_server" }}`, "httpServer", nil},
291+
{"", `{{ toCamelCase "no_https" }}`, "noHttps", nil},
292+
{"", `{{ toCamelCase "all" }}`, "all", nil},
292293
}
293294

294295
runTestCases(t, tests)

0 commit comments

Comments
 (0)