libs/URL.bend
qasim-bend-kit@0.1.0.1 · 44 lines · 0 definitions
1import Base
2
3# Encode one byte as a percent escape. The SQL library used this representation;
4# keeping it preserves existing query and form-body behavior.
5def hex_digit_kind(n: U32, decimal: Bool) -> U32:
6 match decimal:
7 case True{}: (48 + n : U32)
8 case False{}: (55 + n : U32)
9
10def hex_digit(+n: U32) -> U32:
11 hex_digit_kind(n, U32.is_lt(n, 10))
12
13def percent_byte(+byte: U32) -> String:
14 SCon{Chr{37}, SCon{Chr{hex_digit(U32.div(byte, 16))}, SCon{Chr{hex_digit(U32.mod(byte, 16))}, SNil{}}}}
15
16def percent_codepoint_width(+codepoint: U32, width: U32) -> String:
17 match width:
18 case 1: percent_byte(codepoint)
19 case 2: percent_byte((192 + U32.shrn(codepoint, 6n) : U32)) ++
20 percent_byte((128 + U32.and(codepoint, 63) : U32))
21 case 3: percent_byte((224 + U32.shrn(codepoint, 12n) : U32)) ++
22 percent_byte((128 + U32.and(U32.shrn(codepoint, 6n), 63) : U32)) ++
23 percent_byte((128 + U32.and(codepoint, 63) : U32))
24 case _: percent_byte((240 + U32.shrn(codepoint, 18n) : U32)) ++
25 percent_byte((128 + U32.and(U32.shrn(codepoint, 12n), 63) : U32)) ++
26 percent_byte((128 + U32.and(U32.shrn(codepoint, 6n), 63) : U32)) ++
27 percent_byte((128 + U32.and(codepoint, 63) : U32))
28
29def percent_codepoint(+codepoint: U32) -> String:
30 +width = Bool.pick(U32, U32.is_lt(codepoint, 128), 1,
31 Bool.pick(U32, U32.is_lt(codepoint, 2048), 2,
32 Bool.pick(U32, U32.is_lt(codepoint, 65536), 3, 4)))
33 percent_codepoint_width(codepoint, width)
34
35def percent_characters(text: String) -> String:
36 match text:
37 case SNil{}: ""
38 case SCon{Chr{+codepoint}, tail}:
39 percent_codepoint(codepoint) ++ percent_characters(tail)
40
41# Percent-encode a URL component as UTF-8 bytes. This deliberately encodes
42# every byte, matching the former SQL.percent_component behavior.
43def percent_component(text: String) -> String:
44 percent_characters(text)