@ternkit/tern 1.0.0 → 1.2.0
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/dist/goscript/index.svelte.d.ts +44 -0
- package/dist/goscript/index.svelte.js +204 -0
- package/dist/image/Image.svelte +62 -0
- package/dist/image/Image.svelte.d.ts +26 -0
- package/dist/image/types.d.ts +15 -0
- package/dist/image/types.js +1 -0
- package/dist/index.d.ts +14 -1
- package/dist/index.js +5 -1
- package/dist/runtime/api.d.ts +18 -0
- package/dist/runtime/api.js +55 -0
- package/dist/runtime/base.d.ts +2 -0
- package/dist/runtime/base.js +10 -0
- package/dist/runtime/format.d.ts +19 -0
- package/dist/runtime/format.js +279 -0
- package/dist/runtime/i18n.svelte.d.ts +50 -0
- package/dist/runtime/i18n.svelte.js +105 -0
- package/dist/runtime/realtime.svelte.d.ts +78 -0
- package/dist/runtime/realtime.svelte.js +163 -0
- package/dist/runtime/router.svelte.js +16 -0
- package/dist/runtime/types.d.ts +6 -0
- package/dist/server/email.d.ts +18 -0
- package/dist/server/email.js +34 -0
- package/dist/server/index.d.ts +5 -0
- package/dist/server/index.js +6 -0
- package/dist/server/intl.js +1 -1
- package/dist/server/polyfills.d.ts +1 -2
- package/dist/server/polyfills.js +29 -2
- package/dist/server/url.d.ts +56 -0
- package/dist/server/url.js +594 -0
- package/dist/server/web.d.ts +74 -0
- package/dist/server/web.js +395 -0
- package/dist/vite/goscript.d.ts +12 -0
- package/dist/vite/goscript.js +226 -0
- package/dist/vite/image.d.ts +4 -0
- package/dist/vite/image.js +180 -0
- package/dist/vite/index.d.ts +6 -0
- package/dist/vite/index.js +161 -4
- package/package.json +14 -3
|
@@ -0,0 +1,594 @@
|
|
|
1
|
+
// URL and URLSearchParams for the server renderer.
|
|
2
|
+
//
|
|
3
|
+
// QuickJS has no URL. core-js's polyfill keeps each URL's state in a WeakMap
|
|
4
|
+
// whose values point back at their keys, and QuickJS never frees such
|
|
5
|
+
// entries, so every URL that outlives a render leaked. This implementation
|
|
6
|
+
// keeps state in ordinary private fields instead. It covers the WHATWG URL
|
|
7
|
+
// standard for what pages use: special and opaque schemes, relative
|
|
8
|
+
// resolution, dot segments, default ports and percent-encoding. It does not
|
|
9
|
+
// convert international domain names to punycode or parse IPv6 hosts beyond
|
|
10
|
+
// keeping them as written.
|
|
11
|
+
const SPECIAL = { 'http:': '80', 'https:': '443', 'ws:': '80', 'wss:': '443', 'ftp:': '21', 'file:': '' };
|
|
12
|
+
// Percent-encode sets from the URL standard.
|
|
13
|
+
const C0 = (c) => c < 0x20 || c > 0x7e;
|
|
14
|
+
const FRAGMENT = (c) => C0(c) || c === 0x20 || c === 0x22 || c === 0x3c || c === 0x3e || c === 0x60;
|
|
15
|
+
const QUERY = (c) => C0(c) || c === 0x20 || c === 0x22 || c === 0x23 || c === 0x3c || c === 0x3e;
|
|
16
|
+
const SPECIAL_QUERY = (c) => QUERY(c) || c === 0x27;
|
|
17
|
+
const PATH = (c) => QUERY(c) || c === 0x3f || c === 0x60 || c === 0x7b || c === 0x7d || c === 0x5e;
|
|
18
|
+
const USERINFO = (c) => PATH(c) || c === 0x2f || c === 0x3a || c === 0x3b || c === 0x3d || c === 0x40 || (c >= 0x5b && c <= 0x5d) || c === 0x7c;
|
|
19
|
+
// application/x-www-form-urlencoded: everything but *-._ and alphanumerics.
|
|
20
|
+
const FORM = (c) => !((c >= 0x30 && c <= 0x39) || (c >= 0x41 && c <= 0x5a) || (c >= 0x61 && c <= 0x7a) || c === 0x2a || c === 0x2d || c === 0x2e || c === 0x5f);
|
|
21
|
+
const encoder = typeof TextEncoder === 'function' ? new TextEncoder() : null;
|
|
22
|
+
function utf8(s) {
|
|
23
|
+
if (encoder)
|
|
24
|
+
return [...encoder.encode(s)];
|
|
25
|
+
const out = [];
|
|
26
|
+
for (const ch of s) {
|
|
27
|
+
let c = ch.codePointAt(0);
|
|
28
|
+
if (c >= 0xd800 && c <= 0xdfff)
|
|
29
|
+
c = 0xfffd;
|
|
30
|
+
if (c < 0x80)
|
|
31
|
+
out.push(c);
|
|
32
|
+
else if (c < 0x800)
|
|
33
|
+
out.push(0xc0 | (c >> 6), 0x80 | (c & 63));
|
|
34
|
+
else if (c < 0x10000)
|
|
35
|
+
out.push(0xe0 | (c >> 12), 0x80 | ((c >> 6) & 63), 0x80 | (c & 63));
|
|
36
|
+
else
|
|
37
|
+
out.push(0xf0 | (c >> 18), 0x80 | ((c >> 12) & 63), 0x80 | ((c >> 6) & 63), 0x80 | (c & 63));
|
|
38
|
+
}
|
|
39
|
+
return out;
|
|
40
|
+
}
|
|
41
|
+
const HEX = '0123456789ABCDEF';
|
|
42
|
+
function encode(s, set, spaceAsPlus = false) {
|
|
43
|
+
let out = '';
|
|
44
|
+
for (const ch of s) {
|
|
45
|
+
const c = ch.codePointAt(0);
|
|
46
|
+
if (c < 0x80 && !set(c)) {
|
|
47
|
+
out += ch;
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
if (spaceAsPlus && c === 0x20) {
|
|
51
|
+
out += '+';
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
for (const b of utf8(ch))
|
|
55
|
+
out += '%' + HEX[b >> 4] + HEX[b & 15];
|
|
56
|
+
}
|
|
57
|
+
return out;
|
|
58
|
+
}
|
|
59
|
+
function decode(s) {
|
|
60
|
+
const bytes = [];
|
|
61
|
+
for (let i = 0; i < s.length; i++) {
|
|
62
|
+
const c = s.charCodeAt(i);
|
|
63
|
+
if (c === 0x25 && /^[0-9a-fA-F]{2}$/.test(s.slice(i + 1, i + 3))) {
|
|
64
|
+
bytes.push(parseInt(s.slice(i + 1, i + 3), 16));
|
|
65
|
+
i += 2;
|
|
66
|
+
}
|
|
67
|
+
else if (c < 0x80) {
|
|
68
|
+
bytes.push(c);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
bytes.push(...utf8(s[i] + (c >= 0xd800 && c <= 0xdbff ? (s[++i] ?? '') : '')));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return decodeUTF8(bytes);
|
|
75
|
+
}
|
|
76
|
+
function decodeUTF8(bytes) {
|
|
77
|
+
let out = '';
|
|
78
|
+
for (let i = 0; i < bytes.length;) {
|
|
79
|
+
const b = bytes[i];
|
|
80
|
+
let n = 0;
|
|
81
|
+
let c = 0;
|
|
82
|
+
if (b < 0x80)
|
|
83
|
+
[n, c] = [0, b];
|
|
84
|
+
else if (b >= 0xc2 && b < 0xe0)
|
|
85
|
+
[n, c] = [1, b & 31];
|
|
86
|
+
else if (b >= 0xe0 && b < 0xf0)
|
|
87
|
+
[n, c] = [2, b & 15];
|
|
88
|
+
else if (b >= 0xf0 && b < 0xf5)
|
|
89
|
+
[n, c] = [3, b & 7];
|
|
90
|
+
else {
|
|
91
|
+
out += '�';
|
|
92
|
+
i++;
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
let ok = i + n < bytes.length + 0 || n === 0;
|
|
96
|
+
for (let k = 1; k <= n && ok; k++) {
|
|
97
|
+
const cb = bytes[i + k];
|
|
98
|
+
if (cb === undefined || (cb & 0xc0) !== 0x80)
|
|
99
|
+
ok = false;
|
|
100
|
+
else
|
|
101
|
+
c = (c << 6) | (cb & 63);
|
|
102
|
+
}
|
|
103
|
+
if (!ok) {
|
|
104
|
+
out += '�';
|
|
105
|
+
i++;
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
out += String.fromCodePoint(c);
|
|
109
|
+
i += n + 1;
|
|
110
|
+
}
|
|
111
|
+
return out;
|
|
112
|
+
}
|
|
113
|
+
function invalid(input) {
|
|
114
|
+
return new TypeError(`Invalid URL: ${input}`);
|
|
115
|
+
}
|
|
116
|
+
function normalizePath(segments) {
|
|
117
|
+
const out = [];
|
|
118
|
+
for (let i = 0; i < segments.length; i++) {
|
|
119
|
+
const seg = segments[i];
|
|
120
|
+
const lower = seg.toLowerCase();
|
|
121
|
+
const last = i === segments.length - 1;
|
|
122
|
+
if (lower === '..' || lower === '.%2e' || lower === '%2e.' || lower === '%2e%2e') {
|
|
123
|
+
out.pop();
|
|
124
|
+
if (last)
|
|
125
|
+
out.push('');
|
|
126
|
+
}
|
|
127
|
+
else if (lower === '.' || lower === '%2e') {
|
|
128
|
+
if (last)
|
|
129
|
+
out.push('');
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
out.push(encode(seg, PATH));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return out;
|
|
136
|
+
}
|
|
137
|
+
function parseHost(host, special, input) {
|
|
138
|
+
if (host.startsWith('[')) {
|
|
139
|
+
if (!host.endsWith(']'))
|
|
140
|
+
throw invalid(input);
|
|
141
|
+
return host.toLowerCase();
|
|
142
|
+
}
|
|
143
|
+
if (!special)
|
|
144
|
+
return encode(host, C0);
|
|
145
|
+
const h = decode(host).toLowerCase();
|
|
146
|
+
if (h === '' || /[\0\t\n\r #/:<>?@[\\\]^|%]/.test(h))
|
|
147
|
+
throw invalid(input);
|
|
148
|
+
return ipv4(h) ?? h;
|
|
149
|
+
}
|
|
150
|
+
/** Normalizes IPv4 hosts written in decimal, hex or octal parts, as browsers do. */
|
|
151
|
+
function ipv4(h) {
|
|
152
|
+
const parts = h.split('.');
|
|
153
|
+
if (parts[parts.length - 1] === '')
|
|
154
|
+
parts.pop();
|
|
155
|
+
if (parts.length === 0 || parts.length > 4)
|
|
156
|
+
return null;
|
|
157
|
+
const last = parts[parts.length - 1];
|
|
158
|
+
if (!/^(0x[0-9a-f]*|[0-9]+)$/.test(last))
|
|
159
|
+
return null;
|
|
160
|
+
const nums = [];
|
|
161
|
+
for (const p of parts) {
|
|
162
|
+
let n;
|
|
163
|
+
if (/^0x[0-9a-f]*$/.test(p))
|
|
164
|
+
n = p.length === 2 ? 0 : parseInt(p.slice(2), 16);
|
|
165
|
+
else if (/^0[0-7]+$/.test(p))
|
|
166
|
+
n = parseInt(p.slice(1), 8);
|
|
167
|
+
else if (/^[0-9]+$/.test(p))
|
|
168
|
+
n = parseInt(p, 10);
|
|
169
|
+
else
|
|
170
|
+
return null;
|
|
171
|
+
nums.push(n);
|
|
172
|
+
}
|
|
173
|
+
let value = nums.pop();
|
|
174
|
+
if (nums.some((n) => n > 255) || value >= 256 ** (4 - nums.length))
|
|
175
|
+
return null;
|
|
176
|
+
nums.forEach((n, i) => (value += n * 256 ** (3 - i)));
|
|
177
|
+
return [value >>> 24, (value >>> 16) & 255, (value >>> 8) & 255, value & 255].join('.');
|
|
178
|
+
}
|
|
179
|
+
function parse(input, base) {
|
|
180
|
+
// Strip leading and trailing C0 controls and spaces, and all tabs and newlines.
|
|
181
|
+
const raw = input.replace(/^[\u0000- ]+|[\u0000- ]+$/g, '').replace(/[\t\n\r]/g, '');
|
|
182
|
+
let rest = raw;
|
|
183
|
+
let fragment = null;
|
|
184
|
+
const hashAt = rest.indexOf('#');
|
|
185
|
+
if (hashAt >= 0) {
|
|
186
|
+
fragment = encode(rest.slice(hashAt + 1), FRAGMENT);
|
|
187
|
+
rest = rest.slice(0, hashAt);
|
|
188
|
+
}
|
|
189
|
+
const scheme = /^([a-zA-Z][a-zA-Z0-9+.-]*):/.exec(rest);
|
|
190
|
+
if (!scheme) {
|
|
191
|
+
if (!base)
|
|
192
|
+
throw invalid(input);
|
|
193
|
+
return resolve(rest, fragment, base, input);
|
|
194
|
+
}
|
|
195
|
+
const protocol = scheme[1].toLowerCase() + ':';
|
|
196
|
+
rest = rest.slice(scheme[0].length);
|
|
197
|
+
const special = protocol in SPECIAL;
|
|
198
|
+
if (special && base && base.protocol === protocol && !rest.startsWith('/') && !rest.startsWith('\\')) {
|
|
199
|
+
// "http:foo" relative to an http: base.
|
|
200
|
+
return resolve(rest, fragment, base, input);
|
|
201
|
+
}
|
|
202
|
+
if (protocol === 'file:') {
|
|
203
|
+
if (/^[/\\]{2}/.test(rest))
|
|
204
|
+
return withAuthority(protocol, rest.slice(2), fragment, input, true);
|
|
205
|
+
return withAuthority(protocol, rest.replace(/^[/\\]?/, '/'), fragment, input, true);
|
|
206
|
+
}
|
|
207
|
+
if (special)
|
|
208
|
+
return withAuthority(protocol, rest.replace(/^[/\\]*/, ''), fragment, input, false);
|
|
209
|
+
if (rest.startsWith('//'))
|
|
210
|
+
return withAuthority(protocol, rest.slice(2), fragment, input, false);
|
|
211
|
+
if (rest.startsWith('/')) {
|
|
212
|
+
const { path, query } = splitQuery(rest, false);
|
|
213
|
+
return { protocol, username: '', password: '', hostname: '', hasHost: false, port: '', path: normalizePath(path.slice(1).split('/')), opaque: null, query, fragment };
|
|
214
|
+
}
|
|
215
|
+
const { path, query } = splitQuery(rest, false);
|
|
216
|
+
return { protocol, username: '', password: '', hostname: '', hasHost: false, port: '', path: [], opaque: encode(path, C0), query, fragment };
|
|
217
|
+
}
|
|
218
|
+
function splitQuery(s, special) {
|
|
219
|
+
const q = s.indexOf('?');
|
|
220
|
+
if (q < 0)
|
|
221
|
+
return { path: s, query: null };
|
|
222
|
+
return { path: s.slice(0, q), query: encode(s.slice(q + 1), special ? SPECIAL_QUERY : QUERY) };
|
|
223
|
+
}
|
|
224
|
+
function withAuthority(protocol, rest, fragment, input, file) {
|
|
225
|
+
const special = protocol in SPECIAL;
|
|
226
|
+
const end = rest.search(special ? /[/\\?]/ : /[/?]/);
|
|
227
|
+
const authority = end < 0 ? rest : rest.slice(0, end);
|
|
228
|
+
let tail = end < 0 ? '' : rest.slice(end);
|
|
229
|
+
if (special)
|
|
230
|
+
tail = tail.replace(/^[^?]*/, (m) => m.replace(/\\/g, '/'));
|
|
231
|
+
let username = '';
|
|
232
|
+
let password = '';
|
|
233
|
+
let hostport = authority;
|
|
234
|
+
const at = authority.lastIndexOf('@');
|
|
235
|
+
if (at >= 0) {
|
|
236
|
+
const userinfo = authority.slice(0, at);
|
|
237
|
+
hostport = authority.slice(at + 1);
|
|
238
|
+
const colon = userinfo.indexOf(':');
|
|
239
|
+
username = encode(colon < 0 ? userinfo : userinfo.slice(0, colon), USERINFO);
|
|
240
|
+
password = colon < 0 ? '' : encode(userinfo.slice(colon + 1), USERINFO);
|
|
241
|
+
}
|
|
242
|
+
let host = hostport;
|
|
243
|
+
let port = '';
|
|
244
|
+
const portMatch = /:([0-9]*)$/.exec(hostport);
|
|
245
|
+
if (portMatch && !hostport.endsWith(']')) {
|
|
246
|
+
host = hostport.slice(0, portMatch.index);
|
|
247
|
+
if (portMatch[1]) {
|
|
248
|
+
const n = parseInt(portMatch[1], 10);
|
|
249
|
+
if (n > 65535)
|
|
250
|
+
throw invalid(input);
|
|
251
|
+
port = String(n);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
else if (/:[^\]]*$/.test(hostport) && !hostport.startsWith('[')) {
|
|
255
|
+
throw invalid(input);
|
|
256
|
+
}
|
|
257
|
+
if (SPECIAL[protocol] === port)
|
|
258
|
+
port = '';
|
|
259
|
+
if (file && host.toLowerCase() === 'localhost')
|
|
260
|
+
host = '';
|
|
261
|
+
if (special && !file && host === '')
|
|
262
|
+
throw invalid(input);
|
|
263
|
+
const hostname = host === '' ? '' : parseHost(host, special, input);
|
|
264
|
+
const { path, query } = splitQuery(tail, special);
|
|
265
|
+
const segments = path === '' ? (special ? [''] : []) : normalizePath(path.slice(1).split('/'));
|
|
266
|
+
return { protocol, username, password, hostname, hasHost: true, port, path: segments, opaque: null, query, fragment };
|
|
267
|
+
}
|
|
268
|
+
function resolve(rest, fragment, base, input) {
|
|
269
|
+
const special = base.protocol in SPECIAL;
|
|
270
|
+
if (special)
|
|
271
|
+
rest = rest.replace(/\\/g, '/');
|
|
272
|
+
if (base.opaque !== null) {
|
|
273
|
+
if (rest !== '' || fragment === null)
|
|
274
|
+
throw invalid(input);
|
|
275
|
+
return { ...base, fragment };
|
|
276
|
+
}
|
|
277
|
+
if (rest.startsWith('//'))
|
|
278
|
+
return withAuthority(base.protocol, rest.slice(2), fragment, input, base.protocol === 'file:');
|
|
279
|
+
if (rest === '')
|
|
280
|
+
return { ...base, path: [...base.path], fragment };
|
|
281
|
+
if (rest.startsWith('?')) {
|
|
282
|
+
return { ...base, path: [...base.path], query: encode(rest.slice(1), special ? SPECIAL_QUERY : QUERY), fragment };
|
|
283
|
+
}
|
|
284
|
+
const { path, query } = splitQuery(rest, special);
|
|
285
|
+
let segments;
|
|
286
|
+
if (path.startsWith('/')) {
|
|
287
|
+
segments = path.slice(1).split('/');
|
|
288
|
+
}
|
|
289
|
+
else {
|
|
290
|
+
segments = [...base.path.slice(0, -1), ...path.split('/')];
|
|
291
|
+
}
|
|
292
|
+
return { ...base, path: normalizePath(segments), query, fragment };
|
|
293
|
+
}
|
|
294
|
+
function serialize(p, excludeFragment = false) {
|
|
295
|
+
let s = p.protocol;
|
|
296
|
+
if (p.hasHost) {
|
|
297
|
+
s += '//';
|
|
298
|
+
if (p.username || p.password)
|
|
299
|
+
s += p.username + (p.password ? ':' + p.password : '') + '@';
|
|
300
|
+
s += p.hostname + (p.port ? ':' + p.port : '');
|
|
301
|
+
}
|
|
302
|
+
else if (p.opaque === null && p.path.length > 1 && p.path[0] === '') {
|
|
303
|
+
s += '/.';
|
|
304
|
+
}
|
|
305
|
+
s += p.opaque ?? (p.path.length || p.hasHost ? '/' + p.path.join('/') : '');
|
|
306
|
+
if (p.query !== null)
|
|
307
|
+
s += '?' + p.query;
|
|
308
|
+
if (!excludeFragment && p.fragment !== null)
|
|
309
|
+
s += '#' + p.fragment;
|
|
310
|
+
return s;
|
|
311
|
+
}
|
|
312
|
+
export class URLSearchParams {
|
|
313
|
+
#list = [];
|
|
314
|
+
#url = null;
|
|
315
|
+
constructor(init) {
|
|
316
|
+
if (init == null)
|
|
317
|
+
return;
|
|
318
|
+
if (typeof init === 'string') {
|
|
319
|
+
this.#list = parseQuery(init.startsWith('?') ? init.slice(1) : init);
|
|
320
|
+
}
|
|
321
|
+
else if (typeof init[Symbol.iterator] === 'function') {
|
|
322
|
+
for (const pair of init) {
|
|
323
|
+
const [k, v] = [...pair];
|
|
324
|
+
if (pair.length !== 2 && [...pair].length !== 2)
|
|
325
|
+
throw new TypeError('Each pair needs a name and a value');
|
|
326
|
+
this.#list.push([String(k), String(v)]);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
else {
|
|
330
|
+
for (const [k, v] of Object.entries(init))
|
|
331
|
+
this.#list.push([k, String(v)]);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
/** @internal Links the params to their URL, so changes update it. */
|
|
335
|
+
static _link(params, url, query) {
|
|
336
|
+
params.#url = url;
|
|
337
|
+
params.#list = query ? parseQuery(query) : [];
|
|
338
|
+
}
|
|
339
|
+
/** @internal */
|
|
340
|
+
static _reset(params, query) {
|
|
341
|
+
params.#list = query ? parseQuery(query) : [];
|
|
342
|
+
}
|
|
343
|
+
#update() {
|
|
344
|
+
if (this.#url)
|
|
345
|
+
URL._setQuery(this.#url, this.toString());
|
|
346
|
+
}
|
|
347
|
+
get size() {
|
|
348
|
+
return this.#list.length;
|
|
349
|
+
}
|
|
350
|
+
append(name, value) {
|
|
351
|
+
this.#list.push([String(name), String(value)]);
|
|
352
|
+
this.#update();
|
|
353
|
+
}
|
|
354
|
+
delete(name, value) {
|
|
355
|
+
this.#list = this.#list.filter(([k, v]) => !(k === name && (value === undefined || v === String(value))));
|
|
356
|
+
this.#update();
|
|
357
|
+
}
|
|
358
|
+
get(name) {
|
|
359
|
+
return this.#list.find(([k]) => k === name)?.[1] ?? null;
|
|
360
|
+
}
|
|
361
|
+
getAll(name) {
|
|
362
|
+
return this.#list.filter(([k]) => k === name).map(([, v]) => v);
|
|
363
|
+
}
|
|
364
|
+
has(name, value) {
|
|
365
|
+
return this.#list.some(([k, v]) => k === name && (value === undefined || v === String(value)));
|
|
366
|
+
}
|
|
367
|
+
set(name, value) {
|
|
368
|
+
const i = this.#list.findIndex(([k]) => k === name);
|
|
369
|
+
if (i < 0)
|
|
370
|
+
this.#list.push([String(name), String(value)]);
|
|
371
|
+
else {
|
|
372
|
+
this.#list[i] = [String(name), String(value)];
|
|
373
|
+
this.#list = this.#list.filter(([k], j) => j <= i || k !== name);
|
|
374
|
+
}
|
|
375
|
+
this.#update();
|
|
376
|
+
}
|
|
377
|
+
sort() {
|
|
378
|
+
this.#list = this.#list
|
|
379
|
+
.map((e, i) => [e, i])
|
|
380
|
+
.sort(([a, i], [b, j]) => (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : i - j))
|
|
381
|
+
.map(([e]) => e);
|
|
382
|
+
this.#update();
|
|
383
|
+
}
|
|
384
|
+
forEach(fn, thisArg) {
|
|
385
|
+
for (const [k, v] of this.#list)
|
|
386
|
+
fn.call(thisArg, v, k, this);
|
|
387
|
+
}
|
|
388
|
+
*entries() {
|
|
389
|
+
for (const [k, v] of this.#list)
|
|
390
|
+
yield [k, v];
|
|
391
|
+
}
|
|
392
|
+
*keys() {
|
|
393
|
+
for (const [k] of this.#list)
|
|
394
|
+
yield k;
|
|
395
|
+
}
|
|
396
|
+
*values() {
|
|
397
|
+
for (const [, v] of this.#list)
|
|
398
|
+
yield v;
|
|
399
|
+
}
|
|
400
|
+
[Symbol.iterator]() {
|
|
401
|
+
return this.entries();
|
|
402
|
+
}
|
|
403
|
+
toString() {
|
|
404
|
+
return this.#list.map(([k, v]) => encode(k, FORM, true) + '=' + encode(v, FORM, true)).join('&');
|
|
405
|
+
}
|
|
406
|
+
get [Symbol.toStringTag]() {
|
|
407
|
+
return 'URLSearchParams';
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
function parseQuery(q) {
|
|
411
|
+
const out = [];
|
|
412
|
+
for (const part of q.split('&')) {
|
|
413
|
+
if (!part)
|
|
414
|
+
continue;
|
|
415
|
+
const eq = part.indexOf('=');
|
|
416
|
+
const k = eq < 0 ? part : part.slice(0, eq);
|
|
417
|
+
const v = eq < 0 ? '' : part.slice(eq + 1);
|
|
418
|
+
out.push([decode(k.replace(/\+/g, ' ')), decode(v.replace(/\+/g, ' '))]);
|
|
419
|
+
}
|
|
420
|
+
return out;
|
|
421
|
+
}
|
|
422
|
+
export class URL {
|
|
423
|
+
#p;
|
|
424
|
+
#params = null;
|
|
425
|
+
constructor(url, base) {
|
|
426
|
+
const b = base === undefined ? undefined : parse(String(base));
|
|
427
|
+
this.#p = parse(String(url), b);
|
|
428
|
+
}
|
|
429
|
+
static canParse(url, base) {
|
|
430
|
+
try {
|
|
431
|
+
new URL(url, base);
|
|
432
|
+
return true;
|
|
433
|
+
}
|
|
434
|
+
catch {
|
|
435
|
+
return false;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
static parse(url, base) {
|
|
439
|
+
try {
|
|
440
|
+
return new URL(url, base);
|
|
441
|
+
}
|
|
442
|
+
catch {
|
|
443
|
+
return null;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
/** @internal */
|
|
447
|
+
static _setQuery(url, query) {
|
|
448
|
+
url.#p.query = query === '' ? null : query;
|
|
449
|
+
}
|
|
450
|
+
get href() {
|
|
451
|
+
return serialize(this.#p);
|
|
452
|
+
}
|
|
453
|
+
set href(v) {
|
|
454
|
+
this.#p = parse(v);
|
|
455
|
+
if (this.#params)
|
|
456
|
+
URLSearchParams._reset(this.#params, this.#p.query);
|
|
457
|
+
}
|
|
458
|
+
get origin() {
|
|
459
|
+
const p = this.#p;
|
|
460
|
+
if (p.protocol in SPECIAL && p.protocol !== 'file:')
|
|
461
|
+
return p.protocol + '//' + p.hostname + (p.port ? ':' + p.port : '');
|
|
462
|
+
if (p.protocol === 'blob:') {
|
|
463
|
+
try {
|
|
464
|
+
return new URL(p.opaque ?? '').origin;
|
|
465
|
+
}
|
|
466
|
+
catch {
|
|
467
|
+
return 'null';
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
return 'null';
|
|
471
|
+
}
|
|
472
|
+
get protocol() {
|
|
473
|
+
return this.#p.protocol;
|
|
474
|
+
}
|
|
475
|
+
set protocol(v) {
|
|
476
|
+
const m = /^([a-zA-Z][a-zA-Z0-9+.-]*)/.exec(v);
|
|
477
|
+
if (!m)
|
|
478
|
+
return;
|
|
479
|
+
const next = m[1].toLowerCase() + ':';
|
|
480
|
+
if (next in SPECIAL !== this.#p.protocol in SPECIAL)
|
|
481
|
+
return;
|
|
482
|
+
this.#p.protocol = next;
|
|
483
|
+
if (SPECIAL[next] === this.#p.port)
|
|
484
|
+
this.#p.port = '';
|
|
485
|
+
}
|
|
486
|
+
get username() {
|
|
487
|
+
return this.#p.username;
|
|
488
|
+
}
|
|
489
|
+
set username(v) {
|
|
490
|
+
if (this.#p.hasHost && this.#p.hostname)
|
|
491
|
+
this.#p.username = encode(v, USERINFO);
|
|
492
|
+
}
|
|
493
|
+
get password() {
|
|
494
|
+
return this.#p.password;
|
|
495
|
+
}
|
|
496
|
+
set password(v) {
|
|
497
|
+
if (this.#p.hasHost && this.#p.hostname)
|
|
498
|
+
this.#p.password = encode(v, USERINFO);
|
|
499
|
+
}
|
|
500
|
+
get host() {
|
|
501
|
+
return this.#p.hostname + (this.#p.port ? ':' + this.#p.port : '');
|
|
502
|
+
}
|
|
503
|
+
set host(v) {
|
|
504
|
+
if (this.#p.opaque !== null)
|
|
505
|
+
return;
|
|
506
|
+
try {
|
|
507
|
+
const next = parse(this.#p.protocol + '//' + v);
|
|
508
|
+
this.#p.hostname = next.hostname;
|
|
509
|
+
this.#p.port = next.port;
|
|
510
|
+
this.#p.hasHost = true;
|
|
511
|
+
}
|
|
512
|
+
catch {
|
|
513
|
+
// invalid hosts are ignored, as in browsers
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
get hostname() {
|
|
517
|
+
return this.#p.hostname;
|
|
518
|
+
}
|
|
519
|
+
set hostname(v) {
|
|
520
|
+
if (this.#p.opaque !== null)
|
|
521
|
+
return;
|
|
522
|
+
try {
|
|
523
|
+
this.#p.hostname = parse(this.#p.protocol + '//' + v).hostname;
|
|
524
|
+
this.#p.hasHost = true;
|
|
525
|
+
}
|
|
526
|
+
catch {
|
|
527
|
+
// ignored
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
get port() {
|
|
531
|
+
return this.#p.port;
|
|
532
|
+
}
|
|
533
|
+
set port(v) {
|
|
534
|
+
if (!this.#p.hostname || this.#p.protocol === 'file:')
|
|
535
|
+
return;
|
|
536
|
+
const m = /^[0-9]*/.exec(String(v))[0];
|
|
537
|
+
if (m === '') {
|
|
538
|
+
if (String(v) === '')
|
|
539
|
+
this.#p.port = '';
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
const n = parseInt(m, 10);
|
|
543
|
+
if (n > 65535)
|
|
544
|
+
return;
|
|
545
|
+
this.#p.port = SPECIAL[this.#p.protocol] === String(n) ? '' : String(n);
|
|
546
|
+
}
|
|
547
|
+
get pathname() {
|
|
548
|
+
const p = this.#p;
|
|
549
|
+
return p.opaque ?? (p.path.length || p.hasHost ? '/' + p.path.join('/') : '');
|
|
550
|
+
}
|
|
551
|
+
set pathname(v) {
|
|
552
|
+
if (this.#p.opaque !== null)
|
|
553
|
+
return;
|
|
554
|
+
const special = this.#p.protocol in SPECIAL;
|
|
555
|
+
let s = String(v);
|
|
556
|
+
if (special)
|
|
557
|
+
s = s.replace(/\\/g, '/');
|
|
558
|
+
s = s.replace(/[?#]/g, (c) => (c === '?' ? '%3F' : '%23'));
|
|
559
|
+
this.#p.path = normalizePath((s.startsWith('/') ? s.slice(1) : s).split('/'));
|
|
560
|
+
}
|
|
561
|
+
get search() {
|
|
562
|
+
return this.#p.query ? '?' + this.#p.query : '';
|
|
563
|
+
}
|
|
564
|
+
set search(v) {
|
|
565
|
+
const s = String(v);
|
|
566
|
+
const q = s.startsWith('?') ? s.slice(1) : s;
|
|
567
|
+
this.#p.query = s === '' ? null : encode(q, this.#p.protocol in SPECIAL ? SPECIAL_QUERY : QUERY);
|
|
568
|
+
if (this.#params)
|
|
569
|
+
URLSearchParams._reset(this.#params, this.#p.query);
|
|
570
|
+
}
|
|
571
|
+
get searchParams() {
|
|
572
|
+
if (!this.#params) {
|
|
573
|
+
this.#params = new URLSearchParams();
|
|
574
|
+
URLSearchParams._link(this.#params, this, this.#p.query);
|
|
575
|
+
}
|
|
576
|
+
return this.#params;
|
|
577
|
+
}
|
|
578
|
+
get hash() {
|
|
579
|
+
return this.#p.fragment ? '#' + this.#p.fragment : '';
|
|
580
|
+
}
|
|
581
|
+
set hash(v) {
|
|
582
|
+
const s = String(v);
|
|
583
|
+
this.#p.fragment = s === '' ? null : encode(s.startsWith('#') ? s.slice(1) : s, FRAGMENT);
|
|
584
|
+
}
|
|
585
|
+
toString() {
|
|
586
|
+
return this.href;
|
|
587
|
+
}
|
|
588
|
+
toJSON() {
|
|
589
|
+
return this.href;
|
|
590
|
+
}
|
|
591
|
+
get [Symbol.toStringTag]() {
|
|
592
|
+
return 'URL';
|
|
593
|
+
}
|
|
594
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
export declare class TextEncoderPolyfill {
|
|
2
|
+
readonly encoding = "utf-8";
|
|
3
|
+
encode(input?: string): Uint8Array;
|
|
4
|
+
encodeInto(input: string, dest: Uint8Array): {
|
|
5
|
+
read: number;
|
|
6
|
+
written: number;
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
export declare class TextDecoderPolyfill {
|
|
10
|
+
readonly encoding: string;
|
|
11
|
+
readonly fatal: boolean;
|
|
12
|
+
readonly ignoreBOM: boolean;
|
|
13
|
+
constructor(label?: string, options?: {
|
|
14
|
+
fatal?: boolean;
|
|
15
|
+
ignoreBOM?: boolean;
|
|
16
|
+
});
|
|
17
|
+
decode(input?: ArrayBuffer | ArrayBufferView): string;
|
|
18
|
+
}
|
|
19
|
+
export declare class EventPolyfill {
|
|
20
|
+
readonly type: string;
|
|
21
|
+
readonly bubbles: boolean;
|
|
22
|
+
readonly cancelable: boolean;
|
|
23
|
+
readonly composed: boolean;
|
|
24
|
+
readonly timeStamp: number;
|
|
25
|
+
defaultPrevented: boolean;
|
|
26
|
+
target: unknown;
|
|
27
|
+
currentTarget: unknown;
|
|
28
|
+
/** @internal */
|
|
29
|
+
_stop: boolean;
|
|
30
|
+
constructor(type: string, init?: {
|
|
31
|
+
bubbles?: boolean;
|
|
32
|
+
cancelable?: boolean;
|
|
33
|
+
composed?: boolean;
|
|
34
|
+
});
|
|
35
|
+
preventDefault(): void;
|
|
36
|
+
stopPropagation(): void;
|
|
37
|
+
stopImmediatePropagation(): void;
|
|
38
|
+
}
|
|
39
|
+
export declare class CustomEventPolyfill<T = unknown> extends EventPolyfill {
|
|
40
|
+
readonly detail: T | null;
|
|
41
|
+
constructor(type: string, init?: {
|
|
42
|
+
detail?: T;
|
|
43
|
+
bubbles?: boolean;
|
|
44
|
+
cancelable?: boolean;
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
type Listener = ((e: EventPolyfill) => void) | {
|
|
48
|
+
handleEvent(e: EventPolyfill): void;
|
|
49
|
+
};
|
|
50
|
+
export declare class EventTargetPolyfill {
|
|
51
|
+
#private;
|
|
52
|
+
addEventListener(type: string, fn: Listener | null, options?: boolean | {
|
|
53
|
+
once?: boolean;
|
|
54
|
+
signal?: AbortSignalPolyfill;
|
|
55
|
+
}): void;
|
|
56
|
+
removeEventListener(type: string, fn: Listener | null): void;
|
|
57
|
+
dispatchEvent(event: EventPolyfill): boolean;
|
|
58
|
+
}
|
|
59
|
+
export declare class AbortSignalPolyfill extends EventTargetPolyfill {
|
|
60
|
+
aborted: boolean;
|
|
61
|
+
reason: unknown;
|
|
62
|
+
onabort: ((e: EventPolyfill) => void) | null;
|
|
63
|
+
throwIfAborted(): void;
|
|
64
|
+
static abort(reason?: unknown): AbortSignalPolyfill;
|
|
65
|
+
static timeout(): AbortSignalPolyfill;
|
|
66
|
+
static any(signals: AbortSignalPolyfill[]): AbortSignalPolyfill;
|
|
67
|
+
}
|
|
68
|
+
export declare class AbortControllerPolyfill {
|
|
69
|
+
readonly signal: AbortSignalPolyfill;
|
|
70
|
+
abort(reason?: unknown): void;
|
|
71
|
+
}
|
|
72
|
+
/** Installs every missing API on g (globalThis in the renderer). */
|
|
73
|
+
export declare function install(g: Record<string, unknown>): void;
|
|
74
|
+
export {};
|