-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathstringstyle_formatter.go
More file actions
195 lines (179 loc) · 5.08 KB
/
stringstyle_formatter.go
File metadata and controls
195 lines (179 loc) · 5.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
package stringFormatter
import (
"strings"
"unicode"
)
type FormattingStyle string
type CaseSetting int
const (
Camel FormattingStyle = "camel"
Snake FormattingStyle = "snake"
Kebab FormattingStyle = "kebab"
)
const (
ToUpper CaseSetting = 1
ToLower CaseSetting = 2
NoChanges CaseSetting = 3
)
type styleInc struct {
Index int
Style FormattingStyle
}
var styleSigns = map[rune]FormattingStyle{
'_': Snake,
'-': Kebab,
}
// SetStyle is a function that converts text with code to defined code style.
/* Set text like a code style to on from FormattingStyle (Camel, Snake, or Kebab)
* conversion of abbreviations like JSON, USB, and so on is going like a regular text
* for current version, therefore they these abbreviations could be in a different
* case after conversion.
* Case settings apply in the following order : 1 - textCase, 2 - firstSymbol.
* If you are not applying textCase to text converting from Camel to Snake or Kebab
* result is lower case styled text. textCase does not apply to Camel style.
* Parameters:
* - text - pointer to text
* - style - new code style
* - firstSymbol - case settings for first symbol
* - textCase - case settings for whole text except first symbol
* Returns : new string with formatted line
*/
func SetStyle(text *string, style FormattingStyle, firstSymbol CaseSetting, textCase CaseSetting) string {
if text == nil {
return ""
}
sb := strings.Builder{}
sb.Grow(len(*text))
stats := defineFormattingStyle(text)
startIndex := 0
endIndex := 0
// todo UMV think how to process ....
// we could have many stats at the same time, probably we should use some config in the future
// iterate over the map
for _, v := range stats {
endIndex = v.Index
if endIndex < startIndex {
continue
}
sb.WriteString((*text)[startIndex:endIndex])
startIndex = v.Index
switch style {
case Kebab:
sb.WriteString("-")
case Snake:
sb.WriteString("_")
case Camel:
// in case of convert to Camel we should skip v.Index (because it is _ or -)
if v.Style == Camel {
sb.WriteRune(unicode.ToUpper(rune((*text)[endIndex])))
} else {
sb.WriteRune(unicode.ToUpper(rune((*text)[endIndex+1])))
}
startIndex += 1
}
if v.Style != Camel {
startIndex += 1
}
}
sb.WriteString((*text)[startIndex:])
result := strings.Builder{}
if style != Camel {
switch textCase {
case ToUpper:
result.WriteString(strings.ToUpper(sb.String()[1:]))
case ToLower:
result.WriteString(strings.ToLower(sb.String()[1:]))
case NoChanges:
result.WriteString(sb.String()[1:])
}
} else {
result.WriteString(sb.String()[1:])
}
switch firstSymbol {
case ToUpper:
return strings.ToUpper(sb.String()[:1]) + result.String()
case ToLower:
return strings.ToLower(sb.String()[:1]) + result.String()
case NoChanges:
return sb.String()[:1] + result.String()
default:
return sb.String()[:1] + result.String()
}
}
// GetFormattingStyleOptions function that defines formatting style, case of first char and result from string
/*
*
*/
func GetFormattingStyleOptions(style string) (FormattingStyle, CaseSetting, CaseSetting) {
styleLower := strings.ToLower(style)
var formattingStyle FormattingStyle
firstSymbolCase := ToLower
textCase := NoChanges
switch styleLower {
case string(Camel):
formattingStyle = Camel
case string(Snake):
formattingStyle = Snake
case string(Kebab):
formattingStyle = Kebab
}
runes := []rune(style)
firstSymbolIsUpper := isSymbolIsUpper(runes[0])
if firstSymbolIsUpper {
firstSymbolCase = ToUpper
}
if formattingStyle != Camel {
allSymbolsUpperCase := isStringIsUpper(runes)
if allSymbolsUpperCase {
textCase = ToUpper
} else {
textCase = ToLower
}
}
return formattingStyle, firstSymbolCase, textCase
}
// defineFormattingStyle
/* This function defines what formatting style is using in text
* If there are no transitions between symbols then here we have NoFormatting style
* Didn't decide yet what to do if we are having multiple signatures
* i.e. multiple_signs-at-sameTime .
* Parameters:
* - text - a sequence of symbols to check
* Returns: formatting style using in the text
*/
func defineFormattingStyle(text *string) []styleInc {
// symbol analyze, for camel case pattern -> aA, for kebab -> a-a, for snake -> a_a
inclusions := make([]styleInc, 0)
runes := []rune(*text)
for pos, char := range runes {
// define style and add stats
style, ok := styleSigns[char]
if !ok {
// 1. Probably current symbol is not a sign and we should continue
if pos > 0 && pos < len(runes)-1 {
charIsUpperCase := isSymbolIsUpper(char)
prevChar := runes[pos-1]
prevCharIsUpperCase := unicode.IsUpper(prevChar)
if charIsUpperCase && !prevCharIsUpperCase {
style = Camel
}
}
}
if style != "" {
inclusions = append(inclusions, styleInc{Index: pos, Style: style})
}
}
return inclusions
}
func isSymbolIsUpper(symbol rune) bool {
return unicode.IsUpper(symbol) && unicode.IsLetter(symbol)
}
func isStringIsUpper(str []rune) bool {
isUpper := true
for _, r := range str {
if unicode.IsLetter(r) {
isUpper = isUpper && unicode.IsUpper(r)
}
}
return isUpper
}