rsvim-types 0.1.3

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.
@@ -0,0 +1,669 @@
1
+ /**
2
+ * ---
3
+ * title: Web API
4
+ * sidebar_position: 3
5
+ * ---
6
+ *
7
+ * The [globalThis](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/globalThis) global object, compatible with [WinterTC](https://min-common-api.proposal.wintertc.org/) web platform APIs.
8
+ *
9
+ * @see [MDN - Web APIs](https://developer.mozilla.org/docs/Web/API).
10
+ *
11
+ * @packageDocumentation
12
+ */
13
+
14
+ /** @hidden */
15
+ function isNull(arg: any): boolean {
16
+ return arg === undefined || arg === null;
17
+ }
18
+
19
+ /** @hidden */
20
+ function isString(arg: any): boolean {
21
+ return typeof arg === "string";
22
+ }
23
+
24
+ /** @hidden */
25
+ function checkNotNull(arg: any, msg: string) {
26
+ if (isNull(arg)) {
27
+ throw new TypeError(`${msg} cannot be undefined or null`);
28
+ }
29
+ }
30
+
31
+ /** @hidden */
32
+ function checkIsNumber(arg: any, msg: string) {
33
+ if (typeof arg !== "number") {
34
+ throw new TypeError(`${msg} must be a number, but found ${typeof arg}`);
35
+ }
36
+ }
37
+
38
+ /** @hidden */
39
+ function checkIsInteger(arg: any, msg: string) {
40
+ checkIsNumber(arg, msg);
41
+ if (!Number.isInteger(arg)) {
42
+ throw new TypeError(`${msg} must be an integer, but found ${typeof arg}`);
43
+ }
44
+ }
45
+
46
+ /** @hidden */
47
+ function checkIsBoolean(arg: any, msg: string) {
48
+ if (typeof arg !== "boolean") {
49
+ throw new TypeError(`${msg} must be a boolean, but found ${typeof arg}`);
50
+ }
51
+ }
52
+
53
+ /** @hidden */
54
+ function checkIsString(arg: any, msg: string) {
55
+ if (!isString(arg)) {
56
+ throw new TypeError(`${msg} must be a string, but found ${typeof arg}`);
57
+ }
58
+ }
59
+
60
+ /** @hidden */
61
+ function checkIsFunction(arg: any, msg: string) {
62
+ if (typeof arg !== "function") {
63
+ throw new TypeError(`${msg} must be a function, but found ${typeof arg}`);
64
+ }
65
+ }
66
+
67
+ /** @hidden */
68
+ function checkIsObject(arg: any, msg: string) {
69
+ if (typeof arg !== "object") {
70
+ throw new TypeError(`${msg} must be an object, but found ${typeof arg}`);
71
+ }
72
+ }
73
+
74
+ /** @hidden */
75
+ function checkIsUint8Array(arg: any, msg: string) {
76
+ if (!(arg instanceof Uint8Array)) {
77
+ throw new TypeError(`${msg} must be a Uint8Array, buf found ${typeof arg}`);
78
+ }
79
+ }
80
+
81
+ /** @hidden */
82
+ function isTypedArray(arg: any): boolean {
83
+ return (
84
+ arg instanceof Int8Array ||
85
+ arg instanceof Uint8Array ||
86
+ arg instanceof Uint8ClampedArray ||
87
+ arg instanceof Int16Array ||
88
+ arg instanceof Uint16Array ||
89
+ arg instanceof Int32Array ||
90
+ arg instanceof Uint32Array ||
91
+ arg instanceof Float32Array ||
92
+ arg instanceof Float64Array ||
93
+ arg instanceof BigInt64Array ||
94
+ arg instanceof BigUint64Array
95
+ );
96
+ }
97
+
98
+ /** @hidden */
99
+ function isArrayBuffer(arg: any): boolean {
100
+ return arg instanceof ArrayBuffer;
101
+ }
102
+
103
+ /** @hidden */
104
+ function isDataView(arg: any): boolean {
105
+ return arg instanceof DataView;
106
+ }
107
+
108
+ /** @hidden */
109
+ function checkIsArrayBufferFamily(arg: any, msg: string) {
110
+ if (!(isArrayBuffer(arg) || isDataView(arg) || isTypedArray(arg))) {
111
+ throw new TypeError(
112
+ `${msg} must be either ArrayBuffer/DataView/TypedArray, buf found ${typeof arg}`,
113
+ );
114
+ }
115
+ }
116
+
117
+ /** @hidden */
118
+ function checkIsOptions(arg: any, options: any[], msg: string) {
119
+ if (!options.includes(arg)) {
120
+ throw new RangeError(`${msg} is an invalid option: ${arg}`);
121
+ }
122
+ }
123
+
124
+ /** @hidden */
125
+ function boundByIntegers(arg: any, bound: [number, number]) {
126
+ if (arg < bound[0]) {
127
+ return bound[0];
128
+ }
129
+ if (arg > bound[1]) {
130
+ return bound[1];
131
+ }
132
+ return arg;
133
+ }
134
+
135
+ /** @hidden */
136
+ function setDefaultFields(arg: object, defaults: object) {
137
+ for (const [key, val] of Object.entries(defaults)) {
138
+ if (!Object.hasOwn(arg, key)) {
139
+ Object.defineProperty(arg, key, { value: val, writable: true });
140
+ }
141
+ }
142
+ }
143
+
144
+ /**
145
+ * Encode string text into bytes, it only supports "utf-8" encoding.
146
+ *
147
+ * @see {@link !TextEncoder}
148
+ */
149
+ export class TextEncoder {
150
+ /**
151
+ * @example
152
+ * ```javascript
153
+ * const encoder = new TextEncoder();
154
+ * ```
155
+ */
156
+ constructor() {}
157
+
158
+ /**
159
+ * Encode string text to {@link !Uint8Array}.
160
+ *
161
+ * @example
162
+ * ```javascript
163
+ * const encodedBytes = new TextEncoder().encode("Hello, World!");
164
+ * ```
165
+ *
166
+ * @param {string} input - Text that need encode.
167
+ * @returns {Uint8Array} Encoded uint8 bytes array.
168
+ * @throws Throws {@link !TypeError} if input is not a string.
169
+ */
170
+ encode(input: string): Uint8Array {
171
+ checkIsString(input, `"TextEncoder.encode" input`);
172
+
173
+ // @ts-ignore Ignore warning
174
+ return __InternalRsvimGlobalObject.global_encoding_encode(input);
175
+ }
176
+
177
+ /**
178
+ * Encode string text into {@link !Uint8Array}.
179
+ *
180
+ * @param {string} src - Text that need encode.
181
+ * @param {Uint8Array} dest - Destination that receives the encoded uint8 bytes array.
182
+ * @returns {TextEncoder.EncodeIntoResult} Encode result, it contains two numbers: the "read" Unicode code units from src string, and the "written" UTF-8 bytes into the dest buffer.
183
+ * @throws Throws {@link !TypeError} if src is not a string, or dest is not a {@link !Uint8Array}.
184
+ */
185
+ encodeInto(src: string, dest: Uint8Array): TextEncoder.EncodeIntoResult {
186
+ checkIsString(src, `"TextEncoder.encodeInto" src`);
187
+ checkIsUint8Array(dest, `"TextEncoder.encodeInto" dest`);
188
+
189
+ // @ts-ignore Ignore warning
190
+ return __InternalRsvimGlobalObject.global_encoding_encode_into(
191
+ src,
192
+ dest.buffer,
193
+ );
194
+ }
195
+
196
+ /**
197
+ * The encoding used by encoder, this always returns "utf-8".
198
+ */
199
+ get encoding(): string {
200
+ return "utf-8";
201
+ }
202
+ }
203
+
204
+ export namespace TextEncoder {
205
+ /**
206
+ * @see {@link TextEncoder}
207
+ * @inline
208
+ */
209
+ export type EncodeIntoResult = { read: number; written: number };
210
+ }
211
+
212
+ /**
213
+ * Decode bytes array into string text.
214
+ *
215
+ * @see {@link !TextDecoder}
216
+ */
217
+ export class TextDecoder {
218
+ /** @hidden */
219
+ #rid: number | null | undefined;
220
+ /** @hidden */
221
+ #encoding: string;
222
+ /** @hidden */
223
+ #fatal: boolean;
224
+ /** @hidden */
225
+ #ignoreBOM: boolean;
226
+
227
+ /**
228
+ * Create a TextDecoder instance with specified encoding.
229
+ *
230
+ * Per the [WHATWG Encoding Standard](https://encoding.spec.whatwg.org/), the encodings supported by the TextDecoder API are outlined in the tables below. For each encoding, one or more aliases may be used.
231
+ *
232
+ * | Encoding | Aliases |
233
+ * |----------|---------|
234
+ * |'ibm866' | '866', 'cp866', 'csibm866' |
235
+ * |'iso-8859-2' | 'csisolatin2', 'iso-ir-101', 'iso8859-2', 'iso88592', 'iso_8859-2', 'iso_8859-2:1987', 'l2', 'latin2' |
236
+ * |'iso-8859-3' | 'csisolatin3', 'iso-ir-109', 'iso8859-3', 'iso88593', 'iso_8859-3', 'iso_8859-3:1988', 'l3', 'latin3' |
237
+ * | 'iso-8859-4' | 'csisolatin4', 'iso-ir-110', 'iso8859-4', 'iso88594', 'iso_8859-4', 'iso_8859-4:1988', 'l4', 'latin4' |
238
+ * | 'iso-8859-5' | 'csisolatincyrillic', 'cyrillic', 'iso-ir-144', 'iso8859-5', 'iso88595', 'iso_8859-5', 'iso_8859-5:1988' |
239
+ * | 'iso-8859-6' | 'arabic', 'asmo-708', 'csiso88596e', 'csiso88596i', 'csisolatinarabic', 'ecma-114', 'iso-8859-6-e', 'iso-8859-6-i', 'iso-ir-127', 'iso8859-6', 'iso88596', 'iso_8859-6', 'iso_8859-6:1987' |
240
+ * | 'iso-8859-7' | 'csisolatingreek', 'ecma-118', 'elot_928', 'greek', 'greek8', 'iso-ir-126', 'iso8859-7', 'iso88597', 'iso_8859-7', 'iso_8859-7:1987', 'sun_eu_greek' |
241
+ * | 'iso-8859-8' | 'csiso88598e', 'csisolatinhebrew', 'hebrew', 'iso-8859-8-e', 'iso-ir-138', 'iso8859-8', 'iso88598', 'iso_8859-8', 'iso_8859-8:1988', 'visual' |
242
+ * | 'iso-8859-8-i' | 'csiso88598i', 'logical' |
243
+ * | 'iso-8859-10' | 'csisolatin6', 'iso-ir-157', 'iso8859-10', 'iso885910', 'l6', 'latin6' |
244
+ * | 'iso-8859-13' | 'iso8859-13', 'iso885913' |
245
+ * | 'iso-8859-14' | 'iso8859-14', 'iso885914' |
246
+ * | 'iso-8859-15' | 'csisolatin9', 'iso8859-15', 'iso885915', 'iso_8859-15', 'l9' |
247
+ * | 'koi8-r' | 'cskoi8r', 'koi', 'koi8', 'koi8_r' |
248
+ * | 'koi8-u' | 'koi8-ru' |
249
+ * | 'macintosh' | 'csmacintosh', 'mac', 'x-mac-roman' |
250
+ * | 'windows-874' | 'dos-874', 'iso-8859-11', 'iso8859-11', 'iso885911', 'tis-620' |
251
+ * | 'windows-1250' | 'cp1250', 'x-cp1250' |
252
+ * | 'windows-1251' | 'cp1251', 'x-cp1251' |
253
+ * | 'windows-1252' | 'ansi_x3.4-1968', 'ascii', 'cp1252', 'cp819', 'csisolatin1', 'ibm819', 'iso-8859-1', 'iso-ir-100', 'iso8859-1', 'iso88591', 'iso_8859-1', 'iso_8859-1:1987', 'l1', 'latin1', 'us-ascii', 'x-cp1252' |
254
+ * | 'windows-1253' | 'cp1253', 'x-cp1253' |
255
+ * | 'windows-1254' | 'cp1254', 'csisolatin5', 'iso-8859-9', 'iso-ir-148', 'iso8859-9', 'iso88599', 'iso_8859-9', 'iso_8859-9:1989', 'l5', 'latin5', 'x-cp1254' |
256
+ * | 'windows-1255' | 'cp1255', 'x-cp1255' |
257
+ * | 'windows-1256' | 'cp1256', 'x-cp1256' |
258
+ * | 'windows-1257' | 'cp1257', 'x-cp1257' |
259
+ * | 'windows-1258' | 'cp1258', 'x-cp1258' |
260
+ * | 'x-mac-cyrillic' | 'x-mac-ukrainian' |
261
+ * | 'gbk' | 'chinese', 'csgb2312', 'csiso58gb231280', 'gb2312', 'gb_2312', 'gb_2312-80', 'iso-ir-58', 'x-gbk'
262
+ * | 'gb18030' | |
263
+ * | 'big5' | 'big5-hkscs', 'cn-big5', 'csbig5', 'x-x-big5' |
264
+ * | 'euc-jp' | 'cseucpkdfmtjapanese', 'x-euc-jp' |
265
+ * | 'iso-2022-jp' | 'csiso2022jp' |
266
+ * | 'shift_jis' | 'csshiftjis', 'ms932', 'ms_kanji', 'shift-jis', 'sjis', 'windows-31j', 'x-sjis' |
267
+ * | 'euc-kr' | 'cseuckr', 'csksc56011987', 'iso-ir-149', 'korean', 'ks_c_5601-1987', 'ks_c_5601-1989', 'ksc5601', 'ksc_5601', 'windows-949' |
268
+ *
269
+ * @example
270
+ * ```javascript
271
+ * const bytes = new Uint8Array([
272
+ * 0xf0, 0x9d, 0x93, 0xbd,
273
+ * 0xf0, 0x9d, 0x93, 0xae,
274
+ * 0xf0, 0x9d, 0x94, 0x81,
275
+ * 0xf0, 0x9d, 0x93, 0xbd
276
+ * ]);
277
+ * if (new TextDecoder().decode(bytes) !== "𝓽𝓮𝔁𝓽") {
278
+ * Rsvim.cmd.echo("Failed to decode");
279
+ * }
280
+ * ```
281
+ *
282
+ * @see [Node.js - WHATWG supported encodings](https://nodejs.org/api/util.html#whatwg-supported-encodings)
283
+ * @see [encoding_rs - Relationship with Windows Code Pages](https://docs.rs/encoding_rs/latest/encoding_rs/#relationship-with-windows-code-pages)
284
+ * @see [encoding_rs - Supported Encodings](https://docs.rs/encoding_rs/latest/encoding_rs/#statics)
285
+ *
286
+ * @param {string} encoding - (Optional) Decoder encoding, by default is "utf-8".
287
+ * @param {TextDecoder.Options} options - (Optional) Decode options, by default is `{fatal: false, ignoreBOM: false}`.
288
+ * @throws Throws {@link !TypeError} if encoding is not a string or options is invalid. Throw {@link !RangeError} if encoding is unknown or not support.
289
+ */
290
+ constructor(encoding?: string, options?: TextDecoder.Options) {
291
+ encoding = encoding ?? "utf-8";
292
+ checkIsString(encoding, `"TextDecoder.constructor" encoding`);
293
+
294
+ const encodingIsValid =
295
+ // @ts-ignore Ignore warning
296
+ __InternalRsvimGlobalObject.global_encoding_check_encoding_label(
297
+ encoding,
298
+ );
299
+ if (!encodingIsValid) {
300
+ throw new RangeError(
301
+ `"TextDecoder.constructor" encoding is unknown: ${encoding}`,
302
+ );
303
+ }
304
+
305
+ options = options ?? { fatal: false, ignoreBOM: false };
306
+ checkIsObject(options, `"TextDecoder.constructor" options`);
307
+ setDefaultFields(options, { fatal: false, ignoreBOM: false });
308
+ checkIsBoolean(options.fatal, `"TextDecoder.constructor" fatal option`);
309
+ checkIsBoolean(
310
+ options.ignoreBOM,
311
+ `"TextDecoder.constructor" ignoreBOM option`,
312
+ );
313
+
314
+ this.#encoding = encoding;
315
+ this.#fatal = options.fatal as boolean;
316
+ this.#ignoreBOM = options.ignoreBOM as boolean;
317
+
318
+ // The #rid is actually created when calling `decode` API.
319
+ // Since `encoding_rs::Decoder` lifetime only decode one buffer or stream, otherwise it will panic.
320
+ this.#rid = null;
321
+ }
322
+
323
+ /**
324
+ * Decode a bytes array to string text. The bytes array can be a {@link !ArrayBuffer}, {@link !TypedArray} or {@link !DataView}.
325
+ *
326
+ * @example
327
+ * ```javascript
328
+ * // Single pass, non-stream
329
+ * const str1 = new TextDecoder().decode(new Uint8Array([1,2,3,4]));
330
+ *
331
+ * // Stream
332
+ * const decoder = new TextDecoder();
333
+ * let str2 = "";
334
+ * str2 += decoder.decode(new Uint8Array([1]), {stream: true});
335
+ * str2 += decoder.decode(new Uint8Array([2,3]), {stream: true});
336
+ * str2 += decoder.decode(new Uint8Array([4]), {stream: true});
337
+ * str2 += decoder.decode(undefined, {stream: false}); // Flush buffer and finish decoding.
338
+ * ```
339
+ *
340
+ * @see {@link !TextDecoder}
341
+ *
342
+ * @param {(ArrayBuffer | TypedArray | DataView)} input - (Optional) Bytes array, by default is `new Uint8Array()`.
343
+ * @param {TextDecoder.DecodeOptions} options - (Optional) Decode options, by default is `{stream: false}`. When decode a stream data (e.g. read from tcp network) while reading it and cannot determine the end of bytes, should set `stream` option to `true`.
344
+ * @returns {string} Decoded string text.
345
+ * @throws Throws {@link !TypeError} if input is not a Uint8Array, or options is invalid, or the data is malformed and `fatal` option is set.
346
+ */
347
+ decode(
348
+ input?: ArrayBuffer | TypedArray | DataView,
349
+ options?: TextDecoder.DecodeOptions,
350
+ ): string {
351
+ input = input ?? new Uint8Array();
352
+ checkIsArrayBufferFamily(input, `"TextDecoder.decode" input`);
353
+
354
+ let buffer = input as ArrayBuffer;
355
+ if (isTypedArray(input)) {
356
+ // @ts-ignore Ignore warning
357
+ buffer = input.buffer as ArrayBuffer;
358
+ } else if (isDataView(input)) {
359
+ // @ts-ignore Ignore warning
360
+ buffer = input.buffer as ArrayBuffer;
361
+ }
362
+
363
+ options = options ?? { stream: false };
364
+ checkIsObject(options, `"TextDecoder.decode" options`);
365
+ setDefaultFields(options, { stream: false });
366
+ checkIsBoolean(options.stream, `"TextDecoder.decode" stream option`);
367
+
368
+ const stream = options.stream as boolean;
369
+
370
+ try {
371
+ // For non-stream, single pass decoding,
372
+ if (!stream && this.#rid === null) {
373
+ // @ts-ignore Ignore warning
374
+ return __InternalRsvimGlobalObject.global_encoding_decode_single(
375
+ buffer,
376
+ this.#encoding,
377
+ this.#fatal,
378
+ this.#ignoreBOM,
379
+ );
380
+ }
381
+
382
+ if (this.#rid === null) {
383
+ this.#rid =
384
+ // @ts-ignore Ignore warning
385
+ __InternalRsvimGlobalObject.global_encoding_create_stream_decoder(
386
+ this.#encoding,
387
+ this.#ignoreBOM,
388
+ );
389
+ }
390
+
391
+ // @ts-ignore Ignore warning
392
+ return __InternalRsvimGlobalObject.global_encoding_decode_stream(
393
+ buffer,
394
+ this.#rid,
395
+ this.#fatal,
396
+ stream,
397
+ );
398
+ } finally {
399
+ if (!stream && this.#rid !== null) {
400
+ // @ts-ignore Ignore warning
401
+ __InternalRsvimGlobalObject.global_encoding_close_stream_decoder(
402
+ this.#rid,
403
+ );
404
+ this.#rid = null;
405
+ }
406
+ }
407
+ }
408
+
409
+ /**
410
+ * The encoding used by decoder.
411
+ */
412
+ get encoding(): string {
413
+ return this.#encoding;
414
+ }
415
+
416
+ /**
417
+ * Whether throw {@link !TypeError} when decoding error because the data is malformed.
418
+ */
419
+ get fatal(): boolean {
420
+ return this.#fatal;
421
+ }
422
+
423
+ /**
424
+ * Whether ignore unicode "Byte-Order-Mark" (BOM) when decoding the data.
425
+ */
426
+ get ignoreBOM(): boolean {
427
+ return this.#ignoreBOM;
428
+ }
429
+ }
430
+
431
+ export namespace TextDecoder {
432
+ /**
433
+ * @see {@link TextDecoder}
434
+ * @inline
435
+ */
436
+ export type Options = { fatal?: boolean; ignoreBOM?: boolean };
437
+
438
+ /**
439
+ * @see {@link TextDecoder}
440
+ * @inline
441
+ */
442
+ export type DecodeOptions = { stream?: boolean };
443
+ }
444
+
445
+ /**
446
+ * {@link !TypedArray}
447
+ */
448
+ export type TypedArray =
449
+ | Int8Array
450
+ | Uint8Array
451
+ | Uint8ClampedArray
452
+ | Int16Array
453
+ | Uint16Array
454
+ | Int32Array
455
+ | Uint32Array
456
+ | Float32Array
457
+ | Float64Array
458
+ | BigInt64Array
459
+ | BigUint64Array;
460
+
461
+ // Timer API {
462
+
463
+ const TIMEOUT_MAX = Math.pow(2, 31) - 1;
464
+ // In javascript side, `nextTimerId` and `activeTimers` maps to the internal
465
+ // timeout ID returned from rust `global_create_timer` api. This is mostly for
466
+ // being compatible with web api standard, as the standard requires the returned
467
+ // value need to be within the range of 1 to 2,147,483,647.
468
+ // See: <https://developer.mozilla.org/en-US/docs/Web/API/Window/setTimeout>.
469
+ let nextTimerId = 1;
470
+ const activeTimers = new Map();
471
+
472
+ /**
473
+ * Cancel a repeated timer previously established by calling {@link setInterval}.
474
+ *
475
+ * @param {number} id - The ID (integer) which identifies the schedule.
476
+ * @throws Throws {@link !TypeError} if ID is not an integer.
477
+ */
478
+ export function clearInterval(id: number): void {
479
+ // Check parameter's type.
480
+ checkIsInteger(id, `"clearInterval" ID`);
481
+
482
+ if (activeTimers.has(id)) {
483
+ // @ts-ignore Ignore warning
484
+ __InternalRsvimGlobalObject.global_clear_timer(activeTimers.get(id));
485
+ activeTimers.delete(id);
486
+ }
487
+ }
488
+
489
+ /**
490
+ * Set a repeated timer that calls a function, with a fixed time delay between each call.
491
+ *
492
+ * @param {function} callback - A function to be executed every `delay` milliseconds.
493
+ * @param {number} delay - (Optional) The milliseconds that the timer should delay in between execution of the function, by default is `1`.
494
+ * @param {...any} args - (Optional) Additional arguments which are passed through to the function.
495
+ * @returns {number} The ID (integer) which identifies the timer created.
496
+ * @throws Throws {@link !TypeError} if callback is not a function, or delay is neither a number or undefined.
497
+ */
498
+ export function setInterval(
499
+ callback: (...args: any[]) => void,
500
+ delay?: number,
501
+ ...args: any[]
502
+ ): number {
503
+ delay = delay ?? 1;
504
+ checkIsNumber(delay, `"setInterval" delay`);
505
+
506
+ // Coalesce to number or NaN.
507
+ delay *= 1;
508
+
509
+ // Check delay's boundaries.
510
+ delay = boundByIntegers(delay, [1, TIMEOUT_MAX]);
511
+
512
+ // Check if callback is a valid function.
513
+ checkIsFunction(callback, `"setInterval" callback`);
514
+
515
+ // Pin down the correct ID value.
516
+ const id = nextTimerId++;
517
+
518
+ // @ts-ignore Ignore warning
519
+ const timer = __InternalRsvimGlobalObject.global_create_timer(
520
+ () => {
521
+ callback(...args);
522
+ },
523
+ delay,
524
+ true,
525
+ );
526
+
527
+ // Update `activeTimers` map.
528
+ activeTimers.set(id, timer);
529
+
530
+ return id;
531
+ }
532
+
533
+ /**
534
+ * Cancel a timeout previously established by calling {@link setTimeout}.
535
+ *
536
+ * @param {number} id - The ID (integer) which identifies the timer.
537
+ * @throws Throws {@link !TypeError} if ID is not an integer.
538
+ */
539
+ export function clearTimeout(id: number): void {
540
+ // Check parameter's type.
541
+ checkIsInteger(id, `"clearTimeout" ID`);
542
+
543
+ if (activeTimers.has(id)) {
544
+ // @ts-ignore Ignore warning
545
+ __InternalRsvimGlobalObject.global_clear_timer(activeTimers.get(id));
546
+ activeTimers.delete(id);
547
+ }
548
+ }
549
+
550
+ /**
551
+ * Set a timer which executes a function or specified piece of code once the timer expires.
552
+ *
553
+ * @param {function} callback - A function to be executed after the timer expires.
554
+ * @param {number} delay - (Optional) The milliseconds that the timer should wait before the function is executed, by default is `1`.
555
+ * @param {...any} args - (Optional) Additional arguments which are passed through to the function.
556
+ * @returns {number} The ID (integer) which identifies the timer created.
557
+ * @throws Throws {@link !TypeError} if callback is not a function, or delay is neither a number or undefined.
558
+ */
559
+ export function setTimeout(
560
+ callback: (...args: any[]) => void,
561
+ delay: number,
562
+ ...args: any[]
563
+ ): number {
564
+ delay = delay ?? 1;
565
+ checkIsNumber(delay, `"setTimeout" delay`);
566
+
567
+ // Coalesce to number or NaN.
568
+ delay *= 1;
569
+
570
+ // Check delay's boundaries.
571
+ delay = boundByIntegers(delay, [1, TIMEOUT_MAX]);
572
+
573
+ // Check if callback is a valid function.
574
+ checkIsFunction(callback, `"setTimeout" callback`);
575
+
576
+ // Pin down the correct ID value.
577
+ const id = nextTimerId++;
578
+
579
+ // @ts-ignore Ignore warning
580
+ const timer = __InternalRsvimGlobalObject.global_create_timer(
581
+ () => {
582
+ callback(...args);
583
+ activeTimers.delete(id);
584
+ },
585
+ delay,
586
+ false,
587
+ );
588
+
589
+ // Update `activeTimers` map.
590
+ activeTimers.set(id, timer);
591
+
592
+ return id;
593
+ }
594
+
595
+ // Timer API }
596
+
597
+ // Misc API {
598
+
599
+ /**
600
+ * A microtask is a short function which is executed after the function or module which created it exits and
601
+ * only if the JavaScript execution stack is empty, but before returning control to the event loop being used
602
+ * to drive the script's execution environment.
603
+ *
604
+ * @param {function} callback - A function to be executed.
605
+ * @throws Throws {@link !TypeError} if callback is not a function.
606
+ */
607
+ export function queueMicrotask(callback: () => void): void {
608
+ // Note: We wrap `queueMicrotask` and manually emit the exception because
609
+ // v8 doesn't provide any mechanism to handle callback exceptions during
610
+ // the microtask_checkpoint phase.
611
+
612
+ // Check if the callback argument is a valid type.
613
+ checkIsFunction(callback, `"queueMicrotask" callback`);
614
+
615
+ // @ts-ignore Ignore warning
616
+ __InternalRsvimGlobalObject.global_queue_microtask(() => {
617
+ try {
618
+ callback();
619
+ } catch (err) {
620
+ reportError(err);
621
+ }
622
+ });
623
+ }
624
+
625
+ /**
626
+ * Dispatch an uncaught exception. Similar to synchronous version of `setTimeout(() => {throw error;}, 0);`.
627
+ *
628
+ * @param {any} error - Anything to be thrown.
629
+ */
630
+ export function reportError(error: any): void {
631
+ // @ts-ignore Ignore warning
632
+ __InternalRsvimGlobalObject.global_report_error(error);
633
+ }
634
+
635
+ // Misc API }
636
+
637
+ ((globalThis: any) => {
638
+ globalThis.clearTimeout = clearTimeout;
639
+ globalThis.setTimeout = setTimeout;
640
+ globalThis.clearInterval = clearInterval;
641
+ globalThis.setInterval = setInterval;
642
+ globalThis.queueMicrotask = queueMicrotask;
643
+ globalThis.reportError = reportError;
644
+
645
+ globalThis.TextEncoder = TextEncoder;
646
+ globalThis.TextDecoder = TextDecoder;
647
+ })(globalThis as unknown as any);
648
+
649
+ /// Declarations for .d.ts
650
+ declare global {
651
+ // @ts-ignore Ignore warning
652
+ var TextEncoder: typeof TextEncoder;
653
+ // @ts-ignore Ignore warning
654
+ var TextDecoder: typeof TextDecoder;
655
+ function clearInterval(id: number): void;
656
+ function setInterval(
657
+ callback: (...args: any[]) => void,
658
+ delay?: number,
659
+ ...args: any[]
660
+ ): number;
661
+ function clearTimeout(id: number): void;
662
+ function setTimeout(
663
+ callback: (...args: any[]) => void,
664
+ delay: number,
665
+ ...args: any[]
666
+ ): number;
667
+ function queueMicrotask(callback: () => void): void;
668
+ function reportError(error: any): void;
669
+ }