@shd101wyy/yo 0.1.26 → 0.1.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/skills/yo-async-effects/SKILL.md +4 -4
- package/.github/skills/yo-async-effects/async-effects-recipes.md +34 -34
- package/.github/skills/yo-core-patterns/SKILL.md +1 -1
- package/.github/skills/yo-core-patterns/core-patterns-cheatsheet.md +26 -26
- package/.github/skills/yo-project-workflow/SKILL.md +6 -3
- package/.github/skills/yo-project-workflow/workflow-cheatsheet.md +34 -11
- package/.github/skills/yo-syntax/SKILL.md +7 -6
- package/.github/skills/yo-syntax/syntax-cheatsheet.md +73 -60
- package/.github/skills/yo-wasm-integration/wasm-integration-cheatsheet.md +3 -3
- package/README.md +10 -8
- package/out/cjs/index.cjs +456 -438
- package/out/cjs/yo-cli.cjs +576 -543
- package/out/cjs/yo-lsp.cjs +559 -532
- package/out/esm/index.mjs +281 -263
- package/out/types/src/formatter.d.ts +11 -0
- package/out/types/src/lsp/formatting.d.ts +2 -0
- package/out/types/src/tests/formatter.test.d.ts +1 -0
- package/out/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/std/alg/hash.yo +13 -21
- package/std/allocator.yo +25 -40
- package/std/async.yo +3 -7
- package/std/build.yo +105 -151
- package/std/cli/arg_parser.yo +184 -169
- package/std/collections/array_list.yo +350 -314
- package/std/collections/btree_map.yo +142 -131
- package/std/collections/deque.yo +132 -128
- package/std/collections/hash_map.yo +542 -566
- package/std/collections/hash_set.yo +623 -687
- package/std/collections/linked_list.yo +275 -293
- package/std/collections/ordered_map.yo +113 -85
- package/std/collections/priority_queue.yo +73 -73
- package/std/crypto/md5.yo +191 -95
- package/std/crypto/random.yo +56 -64
- package/std/crypto/sha256.yo +151 -107
- package/std/encoding/base64.yo +87 -81
- package/std/encoding/hex.yo +43 -50
- package/std/encoding/html.yo +56 -81
- package/std/encoding/html_char_utils.yo +7 -13
- package/std/encoding/html_entities.yo +2248 -2253
- package/std/encoding/json.yo +316 -224
- package/std/encoding/punycode.yo +86 -116
- package/std/encoding/toml.yo +67 -66
- package/std/encoding/utf16.yo +37 -44
- package/std/env.yo +62 -91
- package/std/error.yo +7 -15
- package/std/fmt/display.yo +5 -9
- package/std/fmt/index.yo +8 -14
- package/std/fmt/to_string.yo +330 -315
- package/std/fmt/writer.yo +58 -87
- package/std/fs/dir.yo +83 -102
- package/std/fs/file.yo +147 -180
- package/std/fs/metadata.yo +45 -78
- package/std/fs/temp.yo +55 -65
- package/std/fs/types.yo +27 -40
- package/std/fs/walker.yo +53 -68
- package/std/gc.yo +5 -8
- package/std/glob.yo +30 -43
- package/std/http/client.yo +107 -120
- package/std/http/http.yo +106 -96
- package/std/http/index.yo +4 -6
- package/std/imm/list.yo +88 -93
- package/std/imm/map.yo +528 -464
- package/std/imm/set.yo +52 -57
- package/std/imm/sorted_map.yo +340 -286
- package/std/imm/sorted_set.yo +57 -63
- package/std/imm/string.yo +404 -345
- package/std/imm/vec.yo +173 -181
- package/std/io/reader.yo +3 -6
- package/std/io/writer.yo +4 -8
- package/std/libc/assert.yo +5 -9
- package/std/libc/ctype.yo +32 -22
- package/std/libc/dirent.yo +26 -25
- package/std/libc/errno.yo +164 -90
- package/std/libc/fcntl.yo +52 -45
- package/std/libc/float.yo +66 -44
- package/std/libc/limits.yo +42 -33
- package/std/libc/math.yo +53 -82
- package/std/libc/signal.yo +72 -47
- package/std/libc/stdatomic.yo +217 -188
- package/std/libc/stdint.yo +5 -29
- package/std/libc/stdio.yo +5 -29
- package/std/libc/stdlib.yo +32 -39
- package/std/libc/string.yo +5 -23
- package/std/libc/sys/stat.yo +58 -56
- package/std/libc/time.yo +5 -19
- package/std/libc/unistd.yo +5 -20
- package/std/libc/wctype.yo +6 -9
- package/std/libc/windows.yo +26 -30
- package/std/log.yo +41 -55
- package/std/net/addr.yo +102 -97
- package/std/net/dns.yo +27 -28
- package/std/net/errors.yo +50 -49
- package/std/net/tcp.yo +113 -124
- package/std/net/udp.yo +55 -66
- package/std/os/env.yo +35 -33
- package/std/os/signal.yo +15 -25
- package/std/path.yo +276 -311
- package/std/prelude.yo +6304 -4315
- package/std/process/command.yo +87 -103
- package/std/process/index.yo +12 -31
- package/std/regex/compiler.yo +196 -95
- package/std/regex/flags.yo +58 -39
- package/std/regex/index.yo +157 -173
- package/std/regex/match.yo +20 -31
- package/std/regex/node.yo +134 -152
- package/std/regex/parser.yo +283 -259
- package/std/regex/unicode.yo +172 -202
- package/std/regex/vm.yo +155 -171
- package/std/string/index.yo +5 -7
- package/std/string/rune.yo +45 -55
- package/std/string/string.yo +937 -964
- package/std/string/string_builder.yo +94 -104
- package/std/string/unicode.yo +46 -64
- package/std/sync/channel.yo +72 -73
- package/std/sync/cond.yo +31 -36
- package/std/sync/mutex.yo +30 -32
- package/std/sync/once.yo +13 -16
- package/std/sync/rwlock.yo +26 -31
- package/std/sync/waitgroup.yo +20 -25
- package/std/sys/advise.yo +16 -24
- package/std/sys/bufio/buf_reader.yo +77 -93
- package/std/sys/bufio/buf_writer.yo +52 -65
- package/std/sys/clock.yo +4 -9
- package/std/sys/constants.yo +77 -61
- package/std/sys/copy.yo +4 -10
- package/std/sys/dir.yo +26 -43
- package/std/sys/dns.yo +41 -61
- package/std/sys/errors.yo +95 -103
- package/std/sys/events.yo +45 -57
- package/std/sys/externs.yo +319 -267
- package/std/sys/fallocate.yo +7 -11
- package/std/sys/fcntl.yo +14 -22
- package/std/sys/file.yo +26 -40
- package/std/sys/future.yo +5 -8
- package/std/sys/iov.yo +12 -25
- package/std/sys/lock.yo +12 -13
- package/std/sys/mmap.yo +38 -43
- package/std/sys/path.yo +3 -8
- package/std/sys/perm.yo +7 -21
- package/std/sys/pipe.yo +5 -12
- package/std/sys/process.yo +23 -29
- package/std/sys/seek.yo +10 -12
- package/std/sys/signal.yo +7 -13
- package/std/sys/signals.yo +52 -35
- package/std/sys/socket.yo +63 -58
- package/std/sys/socketpair.yo +3 -6
- package/std/sys/sockinfo.yo +11 -20
- package/std/sys/statfs.yo +11 -34
- package/std/sys/statx.yo +25 -52
- package/std/sys/sysinfo.yo +15 -20
- package/std/sys/tcp.yo +62 -92
- package/std/sys/temp.yo +5 -9
- package/std/sys/time.yo +5 -15
- package/std/sys/timer.yo +6 -11
- package/std/sys/tty.yo +10 -18
- package/std/sys/udp.yo +22 -39
- package/std/sys/umask.yo +3 -6
- package/std/sys/unix.yo +33 -52
- package/std/testing/bench.yo +49 -52
- package/std/thread.yo +10 -15
- package/std/time/datetime.yo +105 -89
- package/std/time/duration.yo +43 -56
- package/std/time/instant.yo +13 -18
- package/std/time/sleep.yo +5 -9
- package/std/url/index.yo +184 -209
- package/std/worker.yo +6 -10
package/std/url/index.yo
CHANGED
|
@@ -1,137 +1,129 @@
|
|
|
1
1
|
//! URL parsing and formatting per RFC 3986 (simplified).
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
{
|
|
5
|
-
{
|
|
6
|
-
{ Error, AnyError, Exception } :: import "../error";
|
|
7
|
-
|
|
2
|
+
open(import("../string"));
|
|
3
|
+
{ ArrayList } :: import("../collections/array_list");
|
|
4
|
+
{ ToString } :: import("../fmt");
|
|
5
|
+
{ Error, AnyError, Exception } :: import("../error");
|
|
8
6
|
/// Errors that can occur during URL parsing.
|
|
9
7
|
UrlError :: enum(
|
|
10
8
|
EmptyInput,
|
|
11
9
|
MissingScheme,
|
|
12
10
|
InvalidPort,
|
|
13
|
-
InvalidCharacter(pos: usize),
|
|
14
|
-
Other(msg: String)
|
|
11
|
+
InvalidCharacter(pos : usize),
|
|
12
|
+
Other(msg : String)
|
|
15
13
|
);
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
14
|
+
impl(
|
|
15
|
+
UrlError,
|
|
16
|
+
ToString(
|
|
17
|
+
to_string : (
|
|
18
|
+
self ->
|
|
19
|
+
match(
|
|
20
|
+
self,
|
|
21
|
+
.EmptyInput => `URL error: empty input`,
|
|
22
|
+
.MissingScheme => `URL error: missing scheme`,
|
|
23
|
+
.InvalidPort => `URL error: invalid port`,
|
|
24
|
+
.InvalidCharacter(pos) => `URL error: invalid character at position ${pos}`,
|
|
25
|
+
.Other(msg) => `URL error: ${msg}`
|
|
26
|
+
)
|
|
25
27
|
)
|
|
26
28
|
)
|
|
27
|
-
)
|
|
28
|
-
|
|
29
|
+
);
|
|
29
30
|
impl(UrlError, Error());
|
|
30
|
-
|
|
31
31
|
// ============================================================================
|
|
32
32
|
// Url
|
|
33
33
|
// ============================================================================
|
|
34
|
-
|
|
35
34
|
// ASCII constants for URL parsing
|
|
36
|
-
_COLON
|
|
37
|
-
_SLASH
|
|
38
|
-
_QUESTION
|
|
39
|
-
_HASH
|
|
40
|
-
_AT
|
|
41
|
-
_LBRACKET
|
|
42
|
-
_RBRACKET
|
|
43
|
-
_ZERO
|
|
44
|
-
_NINE
|
|
45
|
-
_LOWER_A
|
|
46
|
-
_LOWER_Z
|
|
47
|
-
_UPPER_A
|
|
48
|
-
_UPPER_Z
|
|
49
|
-
_PLUS
|
|
50
|
-
_MINUS
|
|
51
|
-
_DOT
|
|
52
|
-
|
|
35
|
+
_COLON :: u8(58); // ':'
|
|
36
|
+
_SLASH :: u8(47); // '/'
|
|
37
|
+
_QUESTION :: u8(63); // '?'
|
|
38
|
+
_HASH :: u8(35); // '#'
|
|
39
|
+
_AT :: u8(64); // '@'
|
|
40
|
+
_LBRACKET :: u8(91); // '['
|
|
41
|
+
_RBRACKET :: u8(93); // ']'
|
|
42
|
+
_ZERO :: u8(48); // '0'
|
|
43
|
+
_NINE :: u8(57); // '9'
|
|
44
|
+
_LOWER_A :: u8(97); // 'a'
|
|
45
|
+
_LOWER_Z :: u8(122); // 'z'
|
|
46
|
+
_UPPER_A :: u8(65); // 'A'
|
|
47
|
+
_UPPER_Z :: u8(90); // 'Z'
|
|
48
|
+
_PLUS :: u8(43); // '+'
|
|
49
|
+
_MINUS :: u8(45); // '-'
|
|
50
|
+
_DOT :: u8(46); // '.'
|
|
53
51
|
// ============================================================================
|
|
54
52
|
// Helper: parse port number from bytes
|
|
55
53
|
// ============================================================================
|
|
56
|
-
|
|
57
|
-
_parse_port :: (fn(s: str, start: usize, end: usize, using(exn : Exception)) -> u16)({
|
|
54
|
+
_parse_port :: (fn(s : str, start : usize, end : usize, using(exn : Exception)) -> u16)({
|
|
58
55
|
cond(
|
|
59
56
|
(start >= end) => {
|
|
60
|
-
exn.throw(dyn
|
|
57
|
+
exn.throw(dyn(UrlError.InvalidPort));
|
|
61
58
|
},
|
|
62
59
|
true => ()
|
|
63
60
|
);
|
|
64
61
|
val := u32(0);
|
|
65
62
|
i := start;
|
|
66
|
-
while
|
|
63
|
+
while(runtime(i < end), {
|
|
67
64
|
ch := s.bytes(i);
|
|
68
65
|
cond(
|
|
69
66
|
((ch >= _ZERO) && (ch <= _NINE)) => {
|
|
70
|
-
val = ((val * u32(10)) + u32(
|
|
67
|
+
val = ((val * u32(10)) + u32(ch - _ZERO));
|
|
71
68
|
cond(
|
|
72
69
|
(val > u32(65535)) => {
|
|
73
|
-
exn.throw(dyn
|
|
70
|
+
exn.throw(dyn(UrlError.InvalidPort));
|
|
74
71
|
},
|
|
75
72
|
true => ()
|
|
76
73
|
);
|
|
77
74
|
},
|
|
78
75
|
true => {
|
|
79
|
-
exn.throw(dyn
|
|
76
|
+
exn.throw(dyn(UrlError.InvalidPort));
|
|
80
77
|
}
|
|
81
78
|
);
|
|
82
79
|
i = (i + usize(1));
|
|
83
|
-
};
|
|
80
|
+
});
|
|
84
81
|
u16(val)
|
|
85
82
|
});
|
|
86
|
-
|
|
87
83
|
/// Parsed URL with scheme, host, port, path, query, and fragment components.
|
|
88
84
|
Url :: object(
|
|
89
|
-
_scheme
|
|
90
|
-
_host
|
|
91
|
-
_port
|
|
92
|
-
_path
|
|
93
|
-
_query
|
|
85
|
+
_scheme : String,
|
|
86
|
+
_host : Option(String),
|
|
87
|
+
_port : Option(u16),
|
|
88
|
+
_path : String,
|
|
89
|
+
_query : Option(String),
|
|
94
90
|
_fragment : Option(String),
|
|
95
91
|
_userinfo : Option(String)
|
|
96
92
|
);
|
|
97
|
-
|
|
98
|
-
|
|
93
|
+
impl(
|
|
94
|
+
Url,
|
|
99
95
|
// Parse a URL string.
|
|
100
96
|
// Supports: scheme://[userinfo@]host[:port]/path[?query][#fragment]
|
|
101
97
|
// Also supports scheme:path (opaque URIs like mailto:user@example.com)
|
|
102
|
-
parse : (fn(s: str, using(exn : Exception)) -> Url)({
|
|
98
|
+
parse : (fn(s : str, using(exn : Exception)) -> Url)({
|
|
103
99
|
cond(
|
|
104
100
|
(s.len() == usize(0)) => {
|
|
105
|
-
exn.throw(dyn
|
|
101
|
+
exn.throw(dyn(UrlError.EmptyInput));
|
|
106
102
|
},
|
|
107
103
|
true => ()
|
|
108
104
|
);
|
|
109
|
-
|
|
110
105
|
pos := usize(0);
|
|
111
106
|
src_len := s.len();
|
|
112
|
-
|
|
113
107
|
// --- Parse scheme ---
|
|
114
108
|
// scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
|
|
115
109
|
scheme_end := usize(0);
|
|
116
110
|
cond(
|
|
117
111
|
(src_len == usize(0)) => {
|
|
118
|
-
exn.throw(dyn
|
|
112
|
+
exn.throw(dyn(UrlError.MissingScheme));
|
|
119
113
|
},
|
|
120
114
|
true => ()
|
|
121
115
|
);
|
|
122
|
-
|
|
123
116
|
// First char must be a letter
|
|
124
117
|
first := s.bytes(usize(0));
|
|
125
118
|
cond(
|
|
126
|
-
(((
|
|
119
|
+
(((first >= _LOWER_A) && (first <= _LOWER_Z)) || ((first >= _UPPER_A) && (first <= _UPPER_Z))) => (),
|
|
127
120
|
true => {
|
|
128
|
-
exn.throw(dyn
|
|
121
|
+
exn.throw(dyn(UrlError.MissingScheme));
|
|
129
122
|
}
|
|
130
123
|
);
|
|
131
|
-
|
|
132
124
|
i := usize(1);
|
|
133
125
|
found_colon := false;
|
|
134
|
-
while
|
|
126
|
+
while(runtime(i < src_len), {
|
|
135
127
|
ch := s.bytes(i);
|
|
136
128
|
cond(
|
|
137
129
|
(ch == _COLON) => {
|
|
@@ -141,47 +133,43 @@ impl(Url,
|
|
|
141
133
|
},
|
|
142
134
|
(((((first >= _LOWER_A) && (first <= _LOWER_Z)) || ((first >= _UPPER_A) && (first <= _UPPER_Z))) || (((ch >= _LOWER_A) && (ch <= _LOWER_Z)) || ((ch >= _UPPER_A) && (ch <= _UPPER_Z)))) || ((((ch >= _ZERO) && (ch <= _NINE)) || (ch == _PLUS)) || ((ch == _MINUS) || (ch == _DOT)))) => (),
|
|
143
135
|
true => {
|
|
144
|
-
exn.throw(dyn
|
|
136
|
+
exn.throw(dyn(UrlError.MissingScheme));
|
|
145
137
|
}
|
|
146
138
|
);
|
|
147
139
|
i = (i + usize(1));
|
|
148
|
-
};
|
|
140
|
+
});
|
|
149
141
|
cond(
|
|
150
142
|
(!(found_colon)) => {
|
|
151
|
-
exn.throw(dyn
|
|
143
|
+
exn.throw(dyn(UrlError.MissingScheme));
|
|
152
144
|
},
|
|
153
145
|
true => ()
|
|
154
146
|
);
|
|
155
|
-
|
|
156
147
|
scheme_bytes := ArrayList(u8).new();
|
|
157
148
|
j := usize(0);
|
|
158
|
-
while
|
|
149
|
+
while(runtime(j < scheme_end), {
|
|
159
150
|
b := s.bytes(j);
|
|
160
151
|
// Normalize to lowercase
|
|
161
152
|
cond(
|
|
162
|
-
((b >= _UPPER_A) && (b <= _UPPER_Z)) => scheme_bytes.push(
|
|
153
|
+
((b >= _UPPER_A) && (b <= _UPPER_Z)) => scheme_bytes.push(b + u8(32)),
|
|
163
154
|
true => scheme_bytes.push(b)
|
|
164
155
|
);
|
|
165
156
|
j = (j + usize(1));
|
|
166
|
-
};
|
|
157
|
+
});
|
|
167
158
|
scheme := String.from_bytes(scheme_bytes);
|
|
168
|
-
pos = (scheme_end + usize(1));
|
|
169
|
-
|
|
159
|
+
pos = (scheme_end + usize(1)); // skip ':'
|
|
170
160
|
// --- Check for authority (// prefix) ---
|
|
171
161
|
has_authority := false;
|
|
172
162
|
cond(
|
|
173
|
-
(((pos + usize(1)) < src_len) && ((s.bytes(pos) == _SLASH) && (s.bytes(
|
|
163
|
+
(((pos + usize(1)) < src_len) && ((s.bytes(pos) == _SLASH) && (s.bytes(pos + usize(1)) == _SLASH))) => {
|
|
174
164
|
has_authority = true;
|
|
175
|
-
pos = (pos + usize(2));
|
|
165
|
+
pos = (pos + usize(2)); // skip '//'
|
|
176
166
|
},
|
|
177
167
|
true => ()
|
|
178
168
|
);
|
|
179
|
-
|
|
180
|
-
(
|
|
181
|
-
(
|
|
182
|
-
(userinfo : Option(String)) = .None;
|
|
169
|
+
(host : Option(String)) =.None;
|
|
170
|
+
(port : Option(u16)) =.None;
|
|
171
|
+
(userinfo : Option(String)) =.None;
|
|
183
172
|
path_str := String.new();
|
|
184
|
-
|
|
185
173
|
cond(
|
|
186
174
|
has_authority => {
|
|
187
175
|
// --- Parse authority: [userinfo@]host[:port] ---
|
|
@@ -189,7 +177,7 @@ impl(Url,
|
|
|
189
177
|
auth_start := pos;
|
|
190
178
|
auth_end := src_len;
|
|
191
179
|
k := pos;
|
|
192
|
-
while
|
|
180
|
+
while(runtime(k < src_len), {
|
|
193
181
|
ch := s.bytes(k);
|
|
194
182
|
cond(
|
|
195
183
|
(((ch == _SLASH) || (ch == _QUESTION)) || (ch == _HASH)) => {
|
|
@@ -199,100 +187,97 @@ impl(Url,
|
|
|
199
187
|
true => ()
|
|
200
188
|
);
|
|
201
189
|
k = (k + usize(1));
|
|
202
|
-
};
|
|
203
|
-
|
|
190
|
+
});
|
|
204
191
|
// Check for userinfo (look for '@')
|
|
205
192
|
host_start := auth_start;
|
|
206
193
|
m := auth_start;
|
|
207
|
-
while
|
|
194
|
+
while(runtime(m < auth_end), {
|
|
208
195
|
cond(
|
|
209
196
|
(s.bytes(m) == _AT) => {
|
|
210
197
|
// Everything before '@' is userinfo
|
|
211
198
|
ui_bytes := ArrayList(u8).new();
|
|
212
199
|
n := auth_start;
|
|
213
|
-
while
|
|
200
|
+
while(runtime(n < m), {
|
|
214
201
|
ui_bytes.push(s.bytes(n));
|
|
215
202
|
n = (n + usize(1));
|
|
216
|
-
};
|
|
217
|
-
userinfo
|
|
203
|
+
});
|
|
204
|
+
userinfo =.Some(String.from_bytes(ui_bytes));
|
|
218
205
|
host_start = (m + usize(1));
|
|
219
206
|
break;
|
|
220
207
|
},
|
|
221
208
|
true => ()
|
|
222
209
|
);
|
|
223
210
|
m = (m + usize(1));
|
|
224
|
-
};
|
|
225
|
-
|
|
211
|
+
});
|
|
226
212
|
// Parse host[:port]
|
|
227
213
|
// Check for IPv6 literal [...]
|
|
228
214
|
cond(
|
|
229
215
|
((host_start < auth_end) && (s.bytes(host_start) == _LBRACKET)) => {
|
|
230
216
|
// IPv6: find closing ']'
|
|
231
217
|
bracket_end := (host_start + usize(1));
|
|
232
|
-
while
|
|
218
|
+
while(runtime((bracket_end < auth_end) && (s.bytes(bracket_end) != _RBRACKET)), {
|
|
233
219
|
bracket_end = (bracket_end + usize(1));
|
|
234
|
-
};
|
|
235
|
-
|
|
220
|
+
});
|
|
236
221
|
host_bytes := ArrayList(u8).new();
|
|
237
222
|
hh := host_start;
|
|
238
|
-
while
|
|
223
|
+
while(runtime(hh <= bracket_end), {
|
|
239
224
|
cond(
|
|
240
|
-
(hh < auth_end) => {
|
|
225
|
+
(hh < auth_end) => {
|
|
226
|
+
host_bytes.push(s.bytes(hh));
|
|
227
|
+
},
|
|
241
228
|
true => ()
|
|
242
229
|
);
|
|
243
230
|
hh = (hh + usize(1));
|
|
244
|
-
};
|
|
245
|
-
host
|
|
246
|
-
|
|
231
|
+
});
|
|
232
|
+
host =.Some(String.from_bytes(host_bytes));
|
|
247
233
|
// Check for port after ']:'
|
|
248
234
|
after_bracket := (bracket_end + usize(1));
|
|
249
235
|
cond(
|
|
250
236
|
((after_bracket < auth_end) && (s.bytes(after_bracket) == _COLON)) => {
|
|
251
|
-
port
|
|
237
|
+
port =.Some(_parse_port(s, after_bracket + usize(1), auth_end));
|
|
252
238
|
},
|
|
253
239
|
true => ()
|
|
254
240
|
);
|
|
255
241
|
},
|
|
256
242
|
true => {
|
|
257
243
|
// Regular host — find ':' for port
|
|
258
|
-
(colon_pos : Option(usize))
|
|
244
|
+
(colon_pos : Option(usize)) =.None;
|
|
259
245
|
cp := host_start;
|
|
260
|
-
while
|
|
246
|
+
while(runtime(cp < auth_end), {
|
|
261
247
|
cond(
|
|
262
248
|
(s.bytes(cp) == _COLON) => {
|
|
263
|
-
colon_pos
|
|
249
|
+
colon_pos =.Some(cp);
|
|
264
250
|
break;
|
|
265
251
|
},
|
|
266
252
|
true => ()
|
|
267
253
|
);
|
|
268
254
|
cp = (cp + usize(1));
|
|
269
|
-
};
|
|
270
|
-
|
|
271
|
-
|
|
255
|
+
});
|
|
256
|
+
match(
|
|
257
|
+
colon_pos,
|
|
272
258
|
.Some(cp_val) => {
|
|
273
259
|
// host is before colon, port is after
|
|
274
260
|
host_b := ArrayList(u8).new();
|
|
275
261
|
hh2 := host_start;
|
|
276
|
-
while
|
|
262
|
+
while(runtime(hh2 < cp_val), {
|
|
277
263
|
host_b.push(s.bytes(hh2));
|
|
278
264
|
hh2 = (hh2 + usize(1));
|
|
279
|
-
};
|
|
280
|
-
host
|
|
281
|
-
|
|
282
|
-
port = .Some(_parse_port(s, (cp_val + usize(1)), auth_end));
|
|
265
|
+
});
|
|
266
|
+
host =.Some(String.from_bytes(host_b));
|
|
267
|
+
port =.Some(_parse_port(s, cp_val + usize(1), auth_end));
|
|
283
268
|
},
|
|
284
269
|
.None => {
|
|
285
270
|
// No port, entire range is host
|
|
286
271
|
host_b := ArrayList(u8).new();
|
|
287
272
|
hh3 := host_start;
|
|
288
|
-
while
|
|
273
|
+
while(runtime(hh3 < auth_end), {
|
|
289
274
|
host_b.push(s.bytes(hh3));
|
|
290
275
|
hh3 = (hh3 + usize(1));
|
|
291
|
-
};
|
|
276
|
+
});
|
|
292
277
|
h := String.from_bytes(host_b);
|
|
293
278
|
cond(
|
|
294
279
|
(!(h.is_empty())) => {
|
|
295
|
-
host
|
|
280
|
+
host =.Some(h);
|
|
296
281
|
},
|
|
297
282
|
true => ()
|
|
298
283
|
);
|
|
@@ -300,17 +285,15 @@ impl(Url,
|
|
|
300
285
|
);
|
|
301
286
|
}
|
|
302
287
|
);
|
|
303
|
-
|
|
304
288
|
pos = auth_end;
|
|
305
289
|
},
|
|
306
290
|
true => ()
|
|
307
291
|
);
|
|
308
|
-
|
|
309
292
|
// --- Parse path ---
|
|
310
293
|
path_start := pos;
|
|
311
294
|
path_end := src_len;
|
|
312
295
|
pp := pos;
|
|
313
|
-
while
|
|
296
|
+
while(runtime(pp < src_len), {
|
|
314
297
|
ch := s.bytes(pp);
|
|
315
298
|
cond(
|
|
316
299
|
((ch == _QUESTION) || (ch == _HASH)) => {
|
|
@@ -320,31 +303,29 @@ impl(Url,
|
|
|
320
303
|
true => ()
|
|
321
304
|
);
|
|
322
305
|
pp = (pp + usize(1));
|
|
323
|
-
};
|
|
324
|
-
|
|
306
|
+
});
|
|
325
307
|
cond(
|
|
326
308
|
(path_start < path_end) => {
|
|
327
309
|
path_bytes := ArrayList(u8).new();
|
|
328
310
|
pb := path_start;
|
|
329
|
-
while
|
|
311
|
+
while(runtime(pb < path_end), {
|
|
330
312
|
path_bytes.push(s.bytes(pb));
|
|
331
313
|
pb = (pb + usize(1));
|
|
332
|
-
};
|
|
314
|
+
});
|
|
333
315
|
path_str = String.from_bytes(path_bytes);
|
|
334
316
|
},
|
|
335
317
|
true => ()
|
|
336
318
|
);
|
|
337
319
|
pos = path_end;
|
|
338
|
-
|
|
339
320
|
// --- Parse query ---
|
|
340
|
-
(query : Option(String))
|
|
321
|
+
(query : Option(String)) =.None;
|
|
341
322
|
cond(
|
|
342
323
|
((pos < src_len) && (s.bytes(pos) == _QUESTION)) => {
|
|
343
|
-
pos = (pos + usize(1));
|
|
324
|
+
pos = (pos + usize(1)); // skip '?'
|
|
344
325
|
q_start := pos;
|
|
345
326
|
q_end := src_len;
|
|
346
327
|
qq := pos;
|
|
347
|
-
while
|
|
328
|
+
while(runtime(qq < src_len), {
|
|
348
329
|
cond(
|
|
349
330
|
(s.bytes(qq) == _HASH) => {
|
|
350
331
|
q_end = qq;
|
|
@@ -353,152 +334,146 @@ impl(Url,
|
|
|
353
334
|
true => ()
|
|
354
335
|
);
|
|
355
336
|
qq = (qq + usize(1));
|
|
356
|
-
};
|
|
337
|
+
});
|
|
357
338
|
q_bytes := ArrayList(u8).new();
|
|
358
339
|
qb := q_start;
|
|
359
|
-
while
|
|
340
|
+
while(runtime(qb < q_end), {
|
|
360
341
|
q_bytes.push(s.bytes(qb));
|
|
361
342
|
qb = (qb + usize(1));
|
|
362
|
-
};
|
|
363
|
-
query
|
|
343
|
+
});
|
|
344
|
+
query =.Some(String.from_bytes(q_bytes));
|
|
364
345
|
pos = q_end;
|
|
365
346
|
},
|
|
366
347
|
true => ()
|
|
367
348
|
);
|
|
368
|
-
|
|
369
349
|
// --- Parse fragment ---
|
|
370
|
-
(fragment : Option(String))
|
|
350
|
+
(fragment : Option(String)) =.None;
|
|
371
351
|
cond(
|
|
372
352
|
((pos < src_len) && (s.bytes(pos) == _HASH)) => {
|
|
373
|
-
pos = (pos + usize(1));
|
|
353
|
+
pos = (pos + usize(1)); // skip '#'
|
|
374
354
|
f_bytes := ArrayList(u8).new();
|
|
375
355
|
fb := pos;
|
|
376
|
-
while
|
|
356
|
+
while(runtime(fb < src_len), {
|
|
377
357
|
f_bytes.push(s.bytes(fb));
|
|
378
358
|
fb = (fb + usize(1));
|
|
379
|
-
};
|
|
380
|
-
fragment
|
|
359
|
+
});
|
|
360
|
+
fragment =.Some(String.from_bytes(f_bytes));
|
|
381
361
|
},
|
|
382
362
|
true => ()
|
|
383
363
|
);
|
|
384
|
-
|
|
385
364
|
// Ensure authority-based URLs have a path starting with "/" or empty
|
|
386
365
|
cond(
|
|
387
366
|
(has_authority && ((!(path_str.is_empty())) && (path_str.as_bytes().get(usize(0)).unwrap() != _SLASH))) => {
|
|
388
|
-
exn.throw(dyn
|
|
367
|
+
exn.throw(dyn(UrlError.Other(`authority path must start with '/'`)));
|
|
389
368
|
},
|
|
390
369
|
true => ()
|
|
391
370
|
);
|
|
392
|
-
|
|
393
371
|
Self(
|
|
394
|
-
_scheme: scheme,
|
|
395
|
-
_host: host,
|
|
396
|
-
_port: port,
|
|
397
|
-
_path: path_str,
|
|
398
|
-
_query: query,
|
|
399
|
-
_fragment: fragment,
|
|
400
|
-
_userinfo: userinfo
|
|
372
|
+
_scheme : scheme,
|
|
373
|
+
_host : host,
|
|
374
|
+
_port : port,
|
|
375
|
+
_path : path_str,
|
|
376
|
+
_query : query,
|
|
377
|
+
_fragment : fragment,
|
|
378
|
+
_userinfo : userinfo
|
|
401
379
|
)
|
|
402
380
|
}),
|
|
403
|
-
|
|
404
381
|
// --- Accessors ---
|
|
405
|
-
|
|
406
|
-
scheme : (fn(self: Self) -> String)(
|
|
382
|
+
scheme : (fn(self : Self) -> String)(
|
|
407
383
|
self._scheme
|
|
408
384
|
),
|
|
409
|
-
|
|
410
|
-
host : (fn(self: Self) -> Option(String))(
|
|
385
|
+
host : (fn(self : Self) -> Option(String))(
|
|
411
386
|
self._host
|
|
412
387
|
),
|
|
413
|
-
|
|
414
|
-
port : (fn(self: Self) -> Option(u16))(
|
|
388
|
+
port : (fn(self : Self) -> Option(u16))(
|
|
415
389
|
self._port
|
|
416
390
|
),
|
|
417
|
-
|
|
418
|
-
path : (fn(self: Self) -> String)(
|
|
391
|
+
path : (fn(self : Self) -> String)(
|
|
419
392
|
self._path
|
|
420
393
|
),
|
|
421
|
-
|
|
422
|
-
query : (fn(self: Self) -> Option(String))(
|
|
394
|
+
query : (fn(self : Self) -> Option(String))(
|
|
423
395
|
self._query
|
|
424
396
|
),
|
|
425
|
-
|
|
426
|
-
fragment : (fn(self: Self) -> Option(String))(
|
|
397
|
+
fragment : (fn(self : Self) -> Option(String))(
|
|
427
398
|
self._fragment
|
|
428
399
|
),
|
|
429
|
-
|
|
430
|
-
userinfo : (fn(self: Self) -> Option(String))(
|
|
400
|
+
userinfo : (fn(self : Self) -> Option(String))(
|
|
431
401
|
self._userinfo
|
|
432
402
|
),
|
|
433
|
-
|
|
434
403
|
// Returns the host:port as a String, or just host if no port
|
|
435
|
-
host_port : (fn(self: Self) -> Option(String))(
|
|
436
|
-
match(
|
|
437
|
-
.
|
|
404
|
+
host_port : (fn(self : Self) -> Option(String))(
|
|
405
|
+
match(
|
|
406
|
+
self._host,
|
|
407
|
+
.None =>.None,
|
|
438
408
|
.Some(h) =>
|
|
439
|
-
match(
|
|
440
|
-
.
|
|
441
|
-
.
|
|
409
|
+
match(
|
|
410
|
+
self._port,
|
|
411
|
+
.None =>.Some(h),
|
|
412
|
+
.Some(p) =>.Some(`${h}:${p}`)
|
|
442
413
|
)
|
|
443
414
|
)
|
|
444
415
|
),
|
|
445
|
-
|
|
446
416
|
// Returns scheme + "://" + host_port (the origin)
|
|
447
|
-
origin : (fn(self: Self) -> String)(
|
|
448
|
-
match(
|
|
417
|
+
origin : (fn(self : Self) -> String)(
|
|
418
|
+
match(
|
|
419
|
+
self._host,
|
|
449
420
|
.None => self._scheme,
|
|
450
421
|
.Some(h) =>
|
|
451
|
-
match(
|
|
422
|
+
match(
|
|
423
|
+
self._port,
|
|
452
424
|
.None => `${self._scheme}://${h}`,
|
|
453
425
|
.Some(p) => `${self._scheme}://${h}:${p}`
|
|
454
426
|
)
|
|
455
427
|
)
|
|
456
428
|
)
|
|
457
429
|
);
|
|
458
|
-
|
|
459
430
|
// Reconstruct the URL as a String
|
|
460
|
-
impl(
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
.Some(
|
|
469
|
-
result = result.concat(
|
|
431
|
+
impl(
|
|
432
|
+
Url,
|
|
433
|
+
ToString(
|
|
434
|
+
to_string : (
|
|
435
|
+
self -> {
|
|
436
|
+
result := `${self._scheme}:`;
|
|
437
|
+
match(
|
|
438
|
+
self._host,
|
|
439
|
+
.Some(h) => {
|
|
440
|
+
result = result.concat(`//`);
|
|
441
|
+
match(
|
|
442
|
+
self._userinfo,
|
|
443
|
+
.Some(ui) => {
|
|
444
|
+
result = result.concat(ui).concat(`@`);
|
|
445
|
+
},
|
|
446
|
+
.None => ()
|
|
447
|
+
);
|
|
448
|
+
result = result.concat(h);
|
|
449
|
+
match(
|
|
450
|
+
self._port,
|
|
451
|
+
.Some(p) => {
|
|
452
|
+
result = result.concat(`:${p}`);
|
|
453
|
+
},
|
|
454
|
+
.None => ()
|
|
455
|
+
);
|
|
470
456
|
},
|
|
471
457
|
.None => ()
|
|
472
458
|
);
|
|
473
|
-
result = result.concat(
|
|
474
|
-
match(
|
|
475
|
-
.
|
|
476
|
-
|
|
459
|
+
result = result.concat(self._path);
|
|
460
|
+
match(
|
|
461
|
+
self._query,
|
|
462
|
+
.Some(q) => {
|
|
463
|
+
result = result.concat(`?`).concat(q);
|
|
477
464
|
},
|
|
478
465
|
.None => ()
|
|
479
466
|
);
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
match(self._fragment,
|
|
494
|
-
.Some(f) => {
|
|
495
|
-
result = result.concat(`#`).concat(f);
|
|
496
|
-
},
|
|
497
|
-
.None => ()
|
|
498
|
-
);
|
|
499
|
-
|
|
500
|
-
result
|
|
501
|
-
})
|
|
502
|
-
));
|
|
503
|
-
|
|
504
|
-
export Url, UrlError;
|
|
467
|
+
match(
|
|
468
|
+
self._fragment,
|
|
469
|
+
.Some(f) => {
|
|
470
|
+
result = result.concat(`#`).concat(f);
|
|
471
|
+
},
|
|
472
|
+
.None => ()
|
|
473
|
+
);
|
|
474
|
+
result
|
|
475
|
+
}
|
|
476
|
+
)
|
|
477
|
+
)
|
|
478
|
+
);
|
|
479
|
+
export(Url, UrlError);
|