-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathfilter_string.go
More file actions
342 lines (300 loc) · 12.1 KB
/
filter_string.go
File metadata and controls
342 lines (300 loc) · 12.1 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
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
package template
import (
"fmt"
"reflect"
"github.com/kaptinlin/filter"
)
// registerStringFilters registers all string-related filters.
func registerStringFilters() {
// Liquid-standard primary names
defaultRegistry.MustRegister("default", defaultFilter)
defaultRegistry.MustRegister("strip", trimFilter)
defaultRegistry.MustRegister("lstrip", trimLeftFilter)
defaultRegistry.MustRegister("rstrip", trimRightFilter)
defaultRegistry.MustRegister("split", splitFilter)
defaultRegistry.MustRegister("replace", replaceFilter)
defaultRegistry.MustRegister("replace_first", replaceFirstFilter)
defaultRegistry.MustRegister("replace_last", replaceLastFilter)
defaultRegistry.MustRegister("remove", removeFilter)
defaultRegistry.MustRegister("remove_first", removeFirstFilter)
defaultRegistry.MustRegister("remove_last", removeLastFilter)
defaultRegistry.MustRegister("append", appendFilter)
defaultRegistry.MustRegister("prepend", prependFilter)
defaultRegistry.MustRegister("length", lengthFilter)
defaultRegistry.MustRegister("upcase", upperFilter)
defaultRegistry.MustRegister("downcase", lowerFilter)
defaultRegistry.MustRegister("capitalize", capitalizeFilter)
defaultRegistry.MustRegister("escape", escapeFilter)
defaultRegistry.MustRegister("escape_once", escapeOnceFilter)
defaultRegistry.MustRegister("strip_html", stripHTMLFilter)
defaultRegistry.MustRegister("strip_newlines", stripNewlinesFilter)
defaultRegistry.MustRegister("url_encode", urlEncodeFilter)
defaultRegistry.MustRegister("url_decode", urlDecodeFilter)
defaultRegistry.MustRegister("base64_encode", base64EncodeFilter)
defaultRegistry.MustRegister("base64_decode", base64DecodeFilter)
defaultRegistry.MustRegister("truncate", truncateFilter)
defaultRegistry.MustRegister("truncatewords", truncateWordsFilter)
defaultRegistry.MustRegister("slice", sliceFilter)
// Extension filters (non-Liquid)
defaultRegistry.MustRegister("titleize", titleizeFilter)
defaultRegistry.MustRegister("camelize", camelizeFilter)
defaultRegistry.MustRegister("pascalize", pascalizeFilter)
defaultRegistry.MustRegister("dasherize", dasherizeFilter)
defaultRegistry.MustRegister("slugify", slugifyFilter)
defaultRegistry.MustRegister("pluralize", pluralizeFilter)
defaultRegistry.MustRegister("ordinalize", ordinalizeFilter)
// Aliases
defaultRegistry.MustRegister("trim", trimFilter)
defaultRegistry.MustRegister("trim_left", trimLeftFilter)
defaultRegistry.MustRegister("trim_right", trimRightFilter)
defaultRegistry.MustRegister("upper", upperFilter)
defaultRegistry.MustRegister("lower", lowerFilter)
defaultRegistry.MustRegister("h", escapeFilter)
defaultRegistry.MustRegister("truncate_words", truncateWordsFilter)
}
// defaultFilter returns a default value if the input is falsy.
func defaultFilter(value any, args ...any) (any, error) {
if NewValue(value).IsTrue() {
return value, nil
}
if len(args) > 0 {
return args[0], nil
}
return "", nil
}
// trimFilter removes leading and trailing whitespace.
func trimFilter(value any, _ ...any) (any, error) {
return filter.Trim(toString(value)), nil
}
// trimLeftFilter removes leading whitespace.
func trimLeftFilter(value any, _ ...any) (any, error) {
return filter.TrimLeft(toString(value)), nil
}
// trimRightFilter removes trailing whitespace.
func trimRightFilter(value any, _ ...any) (any, error) {
return filter.TrimRight(toString(value)), nil
}
// splitFilter divides a string by a delimiter.
func splitFilter(value any, args ...any) (any, error) {
if len(args) < 1 {
return nil, fmt.Errorf("%w: split filter requires a delimiter argument", ErrInsufficientArgs)
}
return filter.Split(toString(value), toString(args[0])), nil
}
// replaceFilter substitutes all instances of a substring.
func replaceFilter(value any, args ...any) (any, error) {
if len(args) < 2 {
return nil, fmt.Errorf("%w: replace filter requires two arguments (old and new substrings)", ErrInsufficientArgs)
}
oldStr, newStr := toString(args[0]), toString(args[1])
return filter.Replace(toString(value), oldStr, newStr), nil
}
// replaceFirstFilter substitutes the first instance of a substring.
func replaceFirstFilter(value any, args ...any) (any, error) {
if len(args) < 2 {
return nil, fmt.Errorf("%w: replace_first filter requires two arguments (old and new substrings)", ErrInsufficientArgs)
}
return filter.ReplaceFirst(toString(value), toString(args[0]), toString(args[1])), nil
}
// replaceLastFilter substitutes the last instance of a substring.
func replaceLastFilter(value any, args ...any) (any, error) {
if len(args) < 2 {
return nil, fmt.Errorf("%w: replace_last filter requires two arguments (old and new substrings)", ErrInsufficientArgs)
}
return filter.ReplaceLast(toString(value), toString(args[0]), toString(args[1])), nil
}
// removeFilter eliminates all occurrences of a substring.
func removeFilter(value any, args ...any) (any, error) {
if len(args) < 1 {
return nil, fmt.Errorf("%w: remove filter requires a substring argument", ErrInsufficientArgs)
}
return filter.Remove(toString(value), toString(args[0])), nil
}
// removeFirstFilter eliminates the first occurrence of a substring.
func removeFirstFilter(value any, args ...any) (any, error) {
if len(args) < 1 {
return nil, fmt.Errorf("%w: remove_first filter requires a substring argument", ErrInsufficientArgs)
}
return filter.RemoveFirst(toString(value), toString(args[0])), nil
}
// removeLastFilter eliminates the last occurrence of a substring.
func removeLastFilter(value any, args ...any) (any, error) {
if len(args) < 1 {
return nil, fmt.Errorf("%w: remove_last filter requires a substring argument", ErrInsufficientArgs)
}
return filter.RemoveLast(toString(value), toString(args[0])), nil
}
// appendFilter adds characters to the end of a string.
func appendFilter(value any, args ...any) (any, error) {
if len(args) < 1 {
return nil, fmt.Errorf("%w: append filter requires a string to append", ErrInsufficientArgs)
}
return filter.Append(toString(value), toString(args[0])), nil
}
// prependFilter adds characters to the beginning of a string.
func prependFilter(value any, args ...any) (any, error) {
if len(args) < 1 {
return nil, fmt.Errorf("%w: prepend filter requires a string to prepend", ErrInsufficientArgs)
}
return filter.Prepend(toString(value), toString(args[0])), nil
}
// lengthFilter returns the length of a string, slice, array, or map.
func lengthFilter(value any, _ ...any) (any, error) {
v := reflect.ValueOf(value)
//exhaustive:ignore
switch v.Kind() {
case reflect.Slice, reflect.Array, reflect.Map:
return v.Len(), nil
}
return filter.Length(toString(value)), nil
}
// upperFilter converts all characters to uppercase.
func upperFilter(value any, _ ...any) (any, error) {
return filter.Upper(toString(value)), nil
}
// lowerFilter converts all characters to lowercase.
func lowerFilter(value any, _ ...any) (any, error) {
return filter.Lower(toString(value)), nil
}
// titleizeFilter capitalizes the first letter of each word.
func titleizeFilter(value any, _ ...any) (any, error) {
return filter.Titleize(toString(value)), nil
}
// capitalizeFilter capitalizes the first letter of a string and lowercases the rest.
func capitalizeFilter(value any, _ ...any) (any, error) {
return filter.Capitalize(toString(value)), nil
}
// camelizeFilter converts a string to camelCase.
func camelizeFilter(value any, _ ...any) (any, error) {
return filter.Camelize(toString(value)), nil
}
// pascalizeFilter converts a string to PascalCase.
func pascalizeFilter(value any, _ ...any) (any, error) {
return filter.Pascalize(toString(value)), nil
}
// dasherizeFilter transforms a string into a lowercased, dash-separated format.
func dasherizeFilter(value any, _ ...any) (any, error) {
return filter.Dasherize(toString(value)), nil
}
// slugifyFilter converts a string into a URL-friendly slug.
func slugifyFilter(value any, _ ...any) (any, error) {
return filter.Slugify(toString(value)), nil
}
// pluralizeFilter determines the singular or plural form based on a numeric value.
func pluralizeFilter(value any, args ...any) (any, error) {
if len(args) < 2 {
return nil, fmt.Errorf("%w: pluralize filter requires two arguments (singular and plural forms)", ErrInsufficientArgs)
}
count, err := toInteger(value)
if err != nil {
return nil, err
}
singular, plural := toString(args[0]), toString(args[1])
return filter.Pluralize(count, singular, plural), nil
}
// ordinalizeFilter converts a number to its ordinal English form.
func ordinalizeFilter(value any, _ ...any) (any, error) {
n, err := toInteger(value)
if err != nil {
return nil, err
}
return filter.Ordinalize(n), nil
}
// truncateFilter shortens a string to a specified length (default 50).
// An optional second argument specifies the ellipsis string (default "...").
func truncateFilter(value any, args ...any) (any, error) {
maxLen := 50
if len(args) >= 1 {
n, err := toInteger(args[0])
if err != nil {
return nil, err
}
maxLen = n
}
if len(args) >= 2 {
return filter.Truncate(toString(value), maxLen, toString(args[1])), nil
}
return filter.Truncate(toString(value), maxLen), nil
}
// truncateWordsFilter truncates a string to a specified number of words (default 15).
// An optional second argument specifies the ellipsis string (default "...").
func truncateWordsFilter(value any, args ...any) (any, error) {
maxWords := 15
if len(args) >= 1 {
n, err := toInteger(args[0])
if err != nil {
return nil, err
}
maxWords = n
}
if len(args) >= 2 {
return filter.TruncateWords(toString(value), maxWords, toString(args[1])), nil
}
return filter.TruncateWords(toString(value), maxWords), nil
}
// escapeFilter escapes HTML special characters. This built-in variant
// returns a plain string.
//
// Engines using FormatHTML override this with escapeFilterSafe (which
// returns SafeString) so the auto-escape pipeline does not double-escape.
func escapeFilter(value any, _ ...any) (any, error) {
return filter.Escape(toString(value)), nil
}
// escapeOnceFilter escapes HTML without double-escaping already-escaped
// entities. Global variant, returns plain string.
func escapeOnceFilter(value any, _ ...any) (any, error) {
return filter.EscapeOnce(toString(value)), nil
}
// escapeFilterSafe is the HTML-mode variant registered only in an
// engine's private filter registry when FormatHTML is enabled. It returns SafeString so the
// per-template auto-escaper treats the already-escaped content as
// trusted and does not escape it a second time.
func escapeFilterSafe(value any, _ ...any) (any, error) {
return SafeString(filter.Escape(toString(value))), nil
}
// escapeOnceFilterSafe mirrors escapeFilterSafe for escape_once.
func escapeOnceFilterSafe(value any, _ ...any) (any, error) {
return SafeString(filter.EscapeOnce(toString(value))), nil
}
// stripHTMLFilter removes all HTML tags from a string.
func stripHTMLFilter(value any, _ ...any) (any, error) {
return filter.StripHTML(toString(value)), nil
}
// stripNewlinesFilter removes all newline characters from a string.
func stripNewlinesFilter(value any, _ ...any) (any, error) {
return filter.StripNewlines(toString(value)), nil
}
// urlEncodeFilter percent-encodes a string for use in URLs.
func urlEncodeFilter(value any, _ ...any) (any, error) {
return filter.URLEncode(toString(value)), nil
}
// urlDecodeFilter decodes a percent-encoded string.
func urlDecodeFilter(value any, _ ...any) (any, error) {
return filter.URLDecode(toString(value))
}
// base64EncodeFilter encodes a string to Base64.
func base64EncodeFilter(value any, _ ...any) (any, error) {
return filter.Base64Encode(toString(value)), nil
}
// base64DecodeFilter decodes a Base64-encoded string.
func base64DecodeFilter(value any, _ ...any) (any, error) {
return filter.Base64Decode(toString(value))
}
// sliceFilter extracts a substring or sub-slice by offset and optional length.
func sliceFilter(value any, args ...any) (any, error) {
if len(args) < 1 {
return nil, fmt.Errorf("%w: slice filter requires an offset argument", ErrInsufficientArgs)
}
offset, err := toInteger(args[0])
if err != nil {
return nil, err
}
if len(args) >= 2 {
length, err := toInteger(args[1])
if err != nil {
return nil, err
}
return filter.Slice(value, offset, length)
}
return filter.Slice(value, offset)
}