Source file liquid_string.ml
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
open Base
open Liquid_syntax
open Syntax
open Tools
open Helpers
open Encoder
let append _ = function
| String base :: String addition :: _ ->
String (base ^ addition) |> ok
| other -> errc "append accepts 2 strings" other
let base64_decode _ = function
| String s :: _ -> Base64.decode_exn s |> ok_str
| other -> errc "base64_decode accepts a string" other
let base64_encode _ = function
| String s :: _ -> Base64.encode_exn s |> ok_str
| other -> errc "base64_encode accepts a string" other
let base64_url_safe_decode _ = function
| String s :: _ -> Base64.decode_exn s |> decode_url |> ok_str
| other -> errc "base64_decode accepts a string" other
let base64_url_safe_encode _ = function
| String s :: _ -> Base64.encode_exn s |> encode_url |> ok_str
| other -> errc "base64_encode accepts a string" other
let camelcase _ = function
| String s :: _ -> (
let wsexp = ~/"\\s|-|_" in
let words = Re2.rewrite_exn wsexp ~template:" " s |> String.split ~on:' ' in
let cammed = List.map words ~f:String.capitalize |> join in
cammed |> ok_str
)
| other -> errc "camelcase accepts a string" other
let capitalize _ = function
| String s :: _ ->
String.capitalize s |> ok_str
| other -> errc "capitalize accepts a string" other
let downcase _ = function
| String s :: _ -> s |> String.lowercase |> ok_str
| other -> errc "downcase accepts a string" other
let escape _ = function
| String s :: _ -> encode_text s |> ok_str
| other -> errc "escape accepts a string" other
let escape_once _ = function
| String s :: _ -> (
if has_encoded_text s |> not then
encode_text s
else
s
) |> ok_str
| other -> errc "escape_once accepts a string" other
let handleize _ = function
| String s :: _ ->
let trimmed = remove_whitespace Both s in
let special_chars = ~/"[^a-zA-z0-9]+" in
let words = Re2.rewrite_exn special_chars ~template:" " trimmed |> String.split ~on:' ' in
let cleaned = List.filter words ~f:(fun t -> t != "") in
let kebab = List.map cleaned ~f:String.lowercase |> String.concat ~sep:"-" in
kebab |> ok_str
| other -> errc "handleize accepts a string" other
let hmac_sha1 _ = function
| String message :: String hash :: _ ->
let enc = message ^ hash |> Sha1.string |> Sha1.to_hex in
enc |> ok_str
| other -> errc "hmac_sha1 accepts a string and a hash (string)" other
let hmac_sha256 _ = function
| String message :: String hash :: _ ->
let enc = message ^ hash |> Sha256.string |> Sha256.to_hex in
enc |> ok_str
| other -> errc "hmac_sha256 accepts a string and a hash (string)" other
let lstrip _ = function
| String s :: _ -> remove_whitespace Beginning s |> ok_str
| other -> errc "lstrip accepts a string" other
let rstrip _ = function
| String s :: _ -> remove_whitespace End s |> ok_str
| other -> errc "rstrip accepts a string" other
let strip _ = function
| String s :: _ -> remove_whitespace Both s |> ok_str
| other -> errc "strip accepts a string" other
let md5 _ = function
| String s :: _ ->
let enc = s |> Md5_lib.string |> Md5_lib.to_hex in
enc |> ok_str
| other -> errc "md5 accepts a string" other
let newline_to_br _ = function
| String s :: _ -> (
let nl = ~/"\n" in
let r = Re2.rewrite_exn nl ~template:"<br />\n" s in
r |> ok_str
)
| other -> errc "newline_to_br accepts a string" other
let pluralize _ = function
| Number n :: String singular :: String plural :: _ ->
let l = if n = 1. then singular else plural in
l |> ok_str
| other -> errc "pluralize accepts a number, a singular string and a plural string" other
let prepend _ = function
| String base :: String addition :: _ ->
addition ^ base |> ok_str
| other -> errc "prepend accepts 2 strings" other
let remove _ = function
| String haystack :: String needle :: _ ->
let exp = ~/needle in
let res = Re2.rewrite_exn exp haystack ~template:"" in
res |> ok_str
| other -> errc "remove accepts 2 strings" other
let remove_first _ = function
| String haystack :: String needle :: _ ->
let s = String.substr_replace_first haystack ~pattern:needle ~with_:"" in
s |> ok_str
| other -> errc "remove_fist accepts 2 strings" other
let remove_last _ = function
| String haystack :: String needle :: _ ->
let rhaystack, rneedle = String.rev haystack, String.rev needle in
let s = String.substr_replace_first rhaystack ~pattern:rneedle ~with_:"" in
String.rev s |> ok_str
| other -> errc "remove_fist accepts 2 strings" other
let replace _ = function
| String haystack :: String find_needle :: String replace_needle :: _ ->
let exp = ~/find_needle in
let res = Re2.rewrite_exn exp haystack ~template:replace_needle in
res |> ok_str
| other -> errc "replace accepts 3 strings" other
let replace_first _ = function
| String haystack :: String find_needle :: String replace_needle :: _ ->
let s = String.substr_replace_first haystack ~pattern:find_needle ~with_:replace_needle in
s |> ok_str
| other -> errc "replace_first accepts 3 strings" other
let replace_last _ = function
| String haystack :: String find_needle :: String replace_needle :: _ ->
let r_hay, r_find, r_rep = String.rev haystack, String.rev find_needle, String.rev replace_needle in
let s = String.substr_replace_first r_hay ~pattern:r_find ~with_:r_rep in
String.rev s |> ok_str
| other -> errc "replace_last accepts 3 strings" other
let sha1 _ = function
| String message :: _ ->
let enc = message |> Sha1.string |> Sha1.to_hex in
enc |> ok_str
| other -> errc "sha1 accepts a string" other
let sha256 _ = function
| String message :: _ ->
let enc = message |> Sha256.string |> Sha256.to_hex in
enc |> ok_str
| other -> errc "sha256 accepts a string" other
let strip_html _ = function
| String s :: _ -> (
let exp = ~/"<.+?/?>" in
let r = Re2.rewrite_exn exp ~template:"" s in
r |> ok_str
)
| other -> errc "string_html accepts a string" other
let strip_newlines _ = function
| String s :: _ -> (
let exp = ~/"\n" in
let r = Re2.rewrite_exn exp ~template:"" s in
r |> ok_str
)
| other -> errc "strip_newlines accepts a string" other
let truncate _ params =
let do_truncate finisher s chars =
(if String.length s > chars then
(String.sub s ~pos:0 ~len:chars) ^ finisher
else
s
) |> ok_str
in
match params with
| String s :: Number fchars :: String finisher :: _ -> do_truncate finisher s (Float.to_int fchars)
| String s :: Number fchars :: _ -> do_truncate "..." s (Float.to_int fchars)
| other -> errc "truncate accepts a string, a number and an optional finisher value (string)" other
let truncatewords _ params =
let do_truncwords finisher s count =
let words = String.split s ~on:' ' in
(if List.length words > count then
let picked_words = List.sub words ~pos:0 ~len:count |> join_by_space in
picked_words ^ finisher
else
s
) |> ok_str
in
match params with
| String s :: Number fcount :: String finisher :: _ -> do_truncwords finisher s (Float.to_int fcount)
| String s :: Number fcount :: _ -> do_truncwords "..." s (Float.to_int fcount)
| other -> errc "truncatewords accepts a string, a number and an optional finisher value (string)" other
let split _ = function
| String s :: String delim :: _ ->
let literal = Str.split (Str.regexp delim) s |> List.map ~f:(fun x -> String x) in
literal |> ok_list
| other -> errc "split accepts a string and a delimiter (string)" other
let upcase _ = function
| String s :: _ -> s |> String.uppercase |> ok_str
| other -> errc "upcase accepts a string" other
let url_encode _ = function
| String url :: _ -> encode_url url |> ok_str
| other -> errc "url_encode accepts a string" other
let url_decode _ = function
| String url :: _ -> decode_url url |> ok_str
| other -> errc "url_decode accepts a string" other
let url_escape _ = function
| String url :: _ -> escape_url url |> ok_str
| other -> errc "url_escape accepts a string" other
let url_param_escape _ = function
| String url :: _ -> escape_param_url url |> ok_str
| other -> errc "url_param_escape accepts a string" other
let function_from_id = function
| "append" -> Some append
| "base64_decode" -> Some base64_decode
| "base64_encode" -> Some base64_encode
| "base64_url_safe_decode" -> Some base64_url_safe_decode
| "base64_url_safe_encode" -> Some base64_url_safe_encode
| "camelcase" -> Some camelcase
| "capitalize" -> Some capitalize
| "downcase" -> Some downcase
| "escape" -> Some escape
| "escape_once" -> Some escape_once
| "handleize" | "handle" -> Some handleize
| "hmac_sha1" -> Some hmac_sha1
| "hmac_sha256" -> Some hmac_sha256
| "lstrip" -> Some lstrip
| "newline_to_br" -> Some newline_to_br
| "prepend" -> Some prepend
| "pluralize" -> Some pluralize
| "remove" -> Some remove
| "remove_first" -> Some remove_first
| "remove_last" -> Some remove_last
| "replace" -> Some replace
| "replace_first" -> Some replace_first
| "replace_last" -> Some replace_last
| "rstrip" -> Some rstrip
| "strip" -> Some strip
| "strip_html" -> Some strip_html
| "strip_newlines" -> Some strip_newlines
| "split" -> Some split
| "sha1" -> Some sha1
| "sha256" -> Some sha256
| "md5" -> Some md5
| "truncate" -> Some truncate
| "truncatewords" -> Some truncatewords
| "upcase" -> Some upcase
| "url_decode" -> Some url_decode
| "url_encode" -> Some url_encode
| "url_escape" -> Some url_escape
| "url_param_escape" -> Some url_param_escape
| _ -> None