instrumentality 0.0.1

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/README.md ADDED
@@ -0,0 +1,35 @@
1
+ ![white title](./assets/title-white.gif#gh-dark-mode-only)
2
+ ![black title](./assets/title-black.gif#gh-light-mode-only)
3
+
4
+
5
+ ## The INSTRUMENTALITY project
6
+ A utility library for TypeScript/Node.js
7
+
8
+
9
+ #
10
+ ### What is this?
11
+ A combination of files to handle TS/JS by itself, Node and DOM (for web) that provides functions, classes and whatnot to reduce boilerplate for common operations.
12
+
13
+
14
+ #
15
+ ### How to use
16
+ ```sh
17
+ npm install git+https://github.com/clerkburk/ts-instrumentality.git
18
+ ```
19
+ then
20
+ ```ts
21
+ import * as isb from "ts-instrumentality" // Base
22
+ import * as isn from "ts-instrumentality/dom" // Browser (if available)
23
+ import * as isd from "ts-instrumentality/road" // Filesystem using Node.js (if available)
24
+ ```
25
+ thats literally it
26
+
27
+
28
+ #
29
+ ### Other things
30
+ ...?
31
+
32
+
33
+ #
34
+ ### LICENSE
35
+ MIT
package/dist/base.d.ts ADDED
@@ -0,0 +1,146 @@
1
+ /**
2
+ * Subclass of {@link Error} that represents an error thrown from this library, providing a specific name for easier identification.
3
+ */
4
+ export declare class InsErr extends Error {
5
+ name: string;
6
+ }
7
+ /**
8
+ * Retries a function multiple times with optional error handling and abort signal.
9
+ *
10
+ * @param fn_ - The function to be retried.
11
+ * @param maxAttempts_ - The maximum number of attempts to execute the function.
12
+ * @param _cbErr - An optional callback function to be executed after each failed attempt.
13
+ * @param abs_ - An optional AbortSignal to abort the retry process.
14
+ * @returns The result of the function if it succeeds within the allowed attempts.
15
+ * @throws If the maximum number of attempts is exceeded or if the operation is aborted.
16
+ */
17
+ export declare function retry<T>(fn_: () => T, maxAttempts_: number, _cbErr?: () => unknown, abs_?: AbortSignal): Promise<T>;
18
+ /**
19
+ * Asynchronously sleeps for a specified duration, with optional abort signal support.
20
+ *
21
+ * @param ms_ - The number of milliseconds to sleep.
22
+ * @param abs_ - An optional AbortSignal to abort the sleep.
23
+ * @returns A Promise that resolves after the specified duration or rejects if aborted.
24
+ */
25
+ export declare function sleep(ms_: number, abs_?: AbortSignal): Promise<void>;
26
+ /**
27
+ * Helper type to build a tuple of a specified length.
28
+ *
29
+ * @template N - The desired length of the tuple.
30
+ * @template T - The tuple being built (used for recursion).
31
+ */
32
+ type BuildTuple<N extends number, T extends number[] = []> = T['length'] extends N ? T : BuildTuple<N, [...T, T['length']]>;
33
+ /**
34
+ * Helper type to add two number types together.
35
+ *
36
+ * @template A - The first number type.
37
+ * @template B - The second number type.
38
+ */
39
+ export type Add<A extends number, B extends number> = [
40
+ ...BuildTuple<A>,
41
+ ...BuildTuple<B>
42
+ ]['length'];
43
+ /**
44
+ * Helper type to enumerate numbers from 0 to N-1.
45
+ *
46
+ * @template N - The upper limit (exclusive) for the enumeration.
47
+ * @template A - The accumulator array used for recursion.
48
+ */
49
+ export type Enumerate<N extends number, A extends number[] = []> = A['length'] extends N ? A[number] : Enumerate<N, [...A, A['length']]>;
50
+ /**
51
+ * A benchmarking class that provides various time units for measuring elapsed time.
52
+ *
53
+ * The class starts a timer upon instantiation and provides properties to access the elapsed time in different units (milliseconds, seconds, minutes, etc.).
54
+ * The `round` method can be called to record the current elapsed time and restart the timer.
55
+ *
56
+ * @property {@link rounds} - An array that stores the recorded elapsed times from each round.
57
+ * @property {@link timer} - The initial timestamp when the benchmark was created or last reset.
58
+ * @method {@link round} - Records the current elapsed time and restarts the timer.
59
+ * @method {@link reset} - Resets the benchmark timer to the current time and clears recorded rounds.
60
+ * @accessor {@link y} - Elapsed time in years (assuming 365.25 days per year).
61
+ * @accessor {@link mn} - Elapsed time in months (assuming 30.44 days per month).
62
+ * @accessor {@link w} - Elapsed time in weeks.
63
+ * @accessor {@link d} - Elapsed time in days.
64
+ * @accessor {@link h} - Elapsed time in hours.
65
+ * @accessor {@link m} - Elapsed time in minutes.
66
+ * @accessor {@link s} - Elapsed time in seconds.
67
+ * @accessor {@link ms} - Elapsed time in milliseconds.
68
+ * @accessor {@link μs} - Elapsed time in microseconds.
69
+ * @accessor {@link ns} - Elapsed time in nanoseconds.
70
+ * @accessor {@link ps} - Elapsed time in picoseconds.
71
+ */
72
+ export declare class Benchmark {
73
+ /** An array that stores the recorded elapsed times from each round. */
74
+ rounds: number[];
75
+ /** Initializes the benchmark timer to the current time using `performance.now()`. */
76
+ timer: number;
77
+ /** Records the current elapsed time and restarts the timer. */
78
+ round(): void;
79
+ /** Resets the benchmark timer to the current time and clears recorded rounds. */
80
+ reset(): void;
81
+ /** Elapsed time in years (assuming 365.25 days per year). */
82
+ get y(): number;
83
+ /** Elapsed time in months (assuming 30.44 days per month). */
84
+ get mn(): number;
85
+ /** Elapsed time in weeks. */
86
+ get w(): number;
87
+ /** Elapsed time in days. */
88
+ get d(): number;
89
+ /** Elapsed time in hours. */
90
+ get h(): number;
91
+ /** Elapsed time in minutes. */
92
+ get m(): number;
93
+ /** Elapsed time in seconds. */
94
+ get s(): number;
95
+ /** Elapsed time in milliseconds. */
96
+ get ms(): number;
97
+ /** Elapsed time in microseconds. */
98
+ get μs(): number;
99
+ /** Elapsed time in nanoseconds. */
100
+ get ns(): number;
101
+ /** Elapsed time in picoseconds. */
102
+ get ps(): number;
103
+ }
104
+ /**
105
+ * Helper type that represents a view of a Uint8Array, exposing only view methods and properties, along with a readonly index signature for accessing elements.
106
+ */
107
+ export type Uint8ArrayView = Pick<Uint8Array, "at" | "includes" | "indexOf" | "lastIndexOf" | "find" | "findIndex" | "findLast" | "findLastIndex" | "every" | "some" | "forEach" | "entries" | "keys" | "values" | typeof Symbol.iterator | "reduce" | "reduceRight" | "join" | "toLocaleString" | "toString" | "map" | "filter" | "slice" | "toReversed" | "toSorted" | "with" | "length" | "byteLength" | "byteOffset"> & {
108
+ readonly [n: number]: number;
109
+ };
110
+ /** Specific reserved 7-bit values codes that must be escaped when encoding data into base-122, as they are considered illegal in the encoding scheme. */
111
+ export declare const BASE122_ILLEGAL: readonly [0, 10, 13, 34, 38, 92];
112
+ /** Mapping of illegal ascii codes to their corresponding indices in {@link BASE122_ILLEGAL} (reverse lookup). */
113
+ export declare const BASE122_ILLEGAL_INDEX: Readonly<Record<number, number>>;
114
+ /** Shortened payload marker used when escaping an illegal 7-bit value and no subsequent 7-bit chunk is available (the current chunk is reused as payload). */
115
+ export declare const BASE122_SHORT: 7;
116
+ /**
117
+ * Encodes indexed data into a base-122 representation, going as low as 9% overhead for large datasets, making base-64 look pathetic in comparison with its 33% overhead.
118
+ * The encoding process packs 7 bits of data into each character, and uses a two-byte sequence for reserved characters to ensure that the output string remains valid.
119
+ *
120
+ * @remarks The high density of base-122 comes with the trade-off of not being able to use the output string in certain contexts, such as URLs or file names.
121
+ * @param data_ - An array-like object containing the data to be encoded.
122
+ * @returns A string representing the base-122 encoded data.
123
+ * @throws If somehow malformed UTF-8 data is generated, the TextDecoder will throw an error (shouldn't happen if the input is valid).
124
+ * @see {@link decode122} for decoding the base-122 string back into its original byte representation.
125
+ * @see {@link BASE122_ILLEGAL} for the list of reserved characters that are escaped during encoding.
126
+ * @example
127
+ * // (pseudo-code)
128
+ * // build script
129
+ * appendFile(".html", `<script type="text/plain">${encode122(compress(readFile(".jpg")))}</script>`)
130
+ *
131
+ * // HTML
132
+ * <script type="text/plain">!!pƋƸ€€²VӦnKZ6w )jpA</script> // embedd data into HTML without it being interpreted as HTML or JS
133
+ */
134
+ export declare function encode122(data_: ArrayLike<number>): string;
135
+ /**
136
+ * Decodes a base-122 encoded string back into its original byte representation.
137
+ * The decoding process reverses the encoding, extracting 7 bits of data from each character and handling two-byte sequences for illegal characters.
138
+ *
139
+ * @param base122_ - The base-122 encoded string to decode.
140
+ * @returns A Uint8Array containing the original byte data.
141
+ * @throws If an invalid base-122 illegal index is encountered during decoding (shouldn't happen if the input was generated by {@link encode122}).
142
+ * @see {@link encode122} for encoding data into base-122.
143
+ */
144
+ export declare function decode122(base122_: string): Uint8Array;
145
+ export {};
146
+ //# sourceMappingURL=base.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../src/base.ts"],"names":[],"mappings":"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"}
package/dist/base.js ADDED
@@ -0,0 +1,209 @@
1
+ /**
2
+ * Subclass of {@link Error} that represents an error thrown from this library, providing a specific name for easier identification.
3
+ */
4
+ export class InsErr extends Error {
5
+ name = "Instrumentality-Error";
6
+ }
7
+ /**
8
+ * Retries a function multiple times with optional error handling and abort signal.
9
+ *
10
+ * @param fn_ - The function to be retried.
11
+ * @param maxAttempts_ - The maximum number of attempts to execute the function.
12
+ * @param _cbErr - An optional callback function to be executed after each failed attempt.
13
+ * @param abs_ - An optional AbortSignal to abort the retry process.
14
+ * @returns The result of the function if it succeeds within the allowed attempts.
15
+ * @throws If the maximum number of attempts is exceeded or if the operation is aborted.
16
+ */
17
+ export async function retry(fn_, maxAttempts_, _cbErr, abs_) {
18
+ while (--maxAttempts_ >= 0 && !(abs_?.aborted ?? false))
19
+ try {
20
+ return await fn_();
21
+ }
22
+ catch (err) {
23
+ if (maxAttempts_ === 0)
24
+ throw err;
25
+ await _cbErr?.();
26
+ }
27
+ if (maxAttempts_ < 0)
28
+ throw new InsErr("Max attempts exceeded");
29
+ else
30
+ throw new InsErr("Operation aborted");
31
+ }
32
+ /**
33
+ * Asynchronously sleeps for a specified duration, with optional abort signal support.
34
+ *
35
+ * @param ms_ - The number of milliseconds to sleep.
36
+ * @param abs_ - An optional AbortSignal to abort the sleep.
37
+ * @returns A Promise that resolves after the specified duration or rejects if aborted.
38
+ */
39
+ export async function sleep(ms_, abs_) {
40
+ if (abs_?.aborted)
41
+ return Promise.reject(new InsErr("Sleep aborted before start"));
42
+ return new Promise((resolve, reject) => {
43
+ const timeout = setTimeout(() => {
44
+ abs_?.removeEventListener("abort", onAbort);
45
+ resolve();
46
+ }, ms_);
47
+ function onAbort() {
48
+ clearTimeout(timeout);
49
+ abs_?.removeEventListener("abort", onAbort);
50
+ reject(new InsErr("Sleep aborted during wait"));
51
+ }
52
+ abs_?.addEventListener("abort", onAbort, { once: true });
53
+ });
54
+ }
55
+ /**
56
+ * A benchmarking class that provides various time units for measuring elapsed time.
57
+ *
58
+ * The class starts a timer upon instantiation and provides properties to access the elapsed time in different units (milliseconds, seconds, minutes, etc.).
59
+ * The `round` method can be called to record the current elapsed time and restart the timer.
60
+ *
61
+ * @property {@link rounds} - An array that stores the recorded elapsed times from each round.
62
+ * @property {@link timer} - The initial timestamp when the benchmark was created or last reset.
63
+ * @method {@link round} - Records the current elapsed time and restarts the timer.
64
+ * @method {@link reset} - Resets the benchmark timer to the current time and clears recorded rounds.
65
+ * @accessor {@link y} - Elapsed time in years (assuming 365.25 days per year).
66
+ * @accessor {@link mn} - Elapsed time in months (assuming 30.44 days per month).
67
+ * @accessor {@link w} - Elapsed time in weeks.
68
+ * @accessor {@link d} - Elapsed time in days.
69
+ * @accessor {@link h} - Elapsed time in hours.
70
+ * @accessor {@link m} - Elapsed time in minutes.
71
+ * @accessor {@link s} - Elapsed time in seconds.
72
+ * @accessor {@link ms} - Elapsed time in milliseconds.
73
+ * @accessor {@link μs} - Elapsed time in microseconds.
74
+ * @accessor {@link ns} - Elapsed time in nanoseconds.
75
+ * @accessor {@link ps} - Elapsed time in picoseconds.
76
+ */
77
+ export class Benchmark {
78
+ /** An array that stores the recorded elapsed times from each round. */
79
+ rounds = [];
80
+ /** Initializes the benchmark timer to the current time using `performance.now()`. */
81
+ timer = performance.now();
82
+ /** Records the current elapsed time and restarts the timer. */
83
+ round() { this.rounds.push(this.ms); this.timer = performance.now(); }
84
+ /** Resets the benchmark timer to the current time and clears recorded rounds. */
85
+ reset() { this.rounds = []; this.timer = performance.now(); }
86
+ /** Elapsed time in years (assuming 365.25 days per year). */
87
+ get y() { return this.mn / 12; }
88
+ /** Elapsed time in months (assuming 30.44 days per month). */
89
+ get mn() { return this.w / 4; }
90
+ /** Elapsed time in weeks. */
91
+ get w() { return this.d / 7; }
92
+ /** Elapsed time in days. */
93
+ get d() { return this.h / 24; }
94
+ /** Elapsed time in hours. */
95
+ get h() { return this.m / 60; }
96
+ /** Elapsed time in minutes. */
97
+ get m() { return this.s / 60; }
98
+ /** Elapsed time in seconds. */
99
+ get s() { return this.ms / 1000; }
100
+ /** Elapsed time in milliseconds. */
101
+ get ms() { return performance.now() - this.timer; }
102
+ /** Elapsed time in microseconds. */
103
+ get μs() { return this.ms * 1e3; }
104
+ /** Elapsed time in nanoseconds. */
105
+ get ns() { return this.μs * 1e3; }
106
+ /** Elapsed time in picoseconds. */
107
+ get ps() { return this.ns * 1e3; }
108
+ }
109
+ /** Specific reserved 7-bit values codes that must be escaped when encoding data into base-122, as they are considered illegal in the encoding scheme. */
110
+ export const BASE122_ILLEGAL = [0, 10, 13, 34, 38, 92];
111
+ /** Mapping of illegal ascii codes to their corresponding indices in {@link BASE122_ILLEGAL} (reverse lookup). */
112
+ export const BASE122_ILLEGAL_INDEX = {
113
+ 0: 0,
114
+ 10: 1,
115
+ 13: 2,
116
+ 34: 3,
117
+ 38: 4,
118
+ 92: 5,
119
+ };
120
+ /** Shortened payload marker used when escaping an illegal 7-bit value and no subsequent 7-bit chunk is available (the current chunk is reused as payload). */
121
+ export const BASE122_SHORT = 0b111;
122
+ /**
123
+ * Encodes indexed data into a base-122 representation, going as low as 9% overhead for large datasets, making base-64 look pathetic in comparison with its 33% overhead.
124
+ * The encoding process packs 7 bits of data into each character, and uses a two-byte sequence for reserved characters to ensure that the output string remains valid.
125
+ *
126
+ * @remarks The high density of base-122 comes with the trade-off of not being able to use the output string in certain contexts, such as URLs or file names.
127
+ * @param data_ - An array-like object containing the data to be encoded.
128
+ * @returns A string representing the base-122 encoded data.
129
+ * @throws If somehow malformed UTF-8 data is generated, the TextDecoder will throw an error (shouldn't happen if the input is valid).
130
+ * @see {@link decode122} for decoding the base-122 string back into its original byte representation.
131
+ * @see {@link BASE122_ILLEGAL} for the list of reserved characters that are escaped during encoding.
132
+ * @example
133
+ * // (pseudo-code)
134
+ * // build script
135
+ * appendFile(".html", `<script type="text/plain">${encode122(compress(readFile(".jpg")))}</script>`)
136
+ *
137
+ * // HTML
138
+ * <script type="text/plain">!!pƋƸ€€²VӦnKZ6w )jpA</script> // embedd data into HTML without it being interpreted as HTML or JS
139
+ */
140
+ export function encode122(data_) {
141
+ const out = [];
142
+ let byteIndex = 0;
143
+ let bitIndex = 0;
144
+ function next7() {
145
+ if (byteIndex >= data_.length)
146
+ return undefined;
147
+ const first = data_[byteIndex];
148
+ const head = (((0b11111110 >>> bitIndex) & first) << bitIndex) >>> 1;
149
+ bitIndex += 7;
150
+ if (bitIndex < 8)
151
+ return head;
152
+ bitIndex -= 8;
153
+ byteIndex++;
154
+ if (byteIndex >= data_.length)
155
+ return head;
156
+ const tail = ((((0xff00 >>> bitIndex) & data_[byteIndex]) & 0xff) >>> (8 - bitIndex));
157
+ return head | tail;
158
+ }
159
+ for (let value = next7(); value !== undefined; value = next7()) {
160
+ const illegalIndex = BASE122_ILLEGAL_INDEX[value];
161
+ if (illegalIndex === undefined)
162
+ out.push(value);
163
+ else {
164
+ const next = next7();
165
+ const payload = next ?? value;
166
+ out.push(0b11000010 | ((next === undefined ? BASE122_SHORT : illegalIndex) << 2) | (payload >>> 6), 0b10000000 | (payload & 0b00111111));
167
+ }
168
+ }
169
+ return new TextDecoder("utf-8", { fatal: true }).decode(Uint8Array.from(out));
170
+ }
171
+ /**
172
+ * Decodes a base-122 encoded string back into its original byte representation.
173
+ * The decoding process reverses the encoding, extracting 7 bits of data from each character and handling two-byte sequences for illegal characters.
174
+ *
175
+ * @param base122_ - The base-122 encoded string to decode.
176
+ * @returns A Uint8Array containing the original byte data.
177
+ * @throws If an invalid base-122 illegal index is encountered during decoding (shouldn't happen if the input was generated by {@link encode122}).
178
+ * @see {@link encode122} for encoding data into base-122.
179
+ */
180
+ export function decode122(base122_) {
181
+ const out = [];
182
+ let current = 0;
183
+ let bitIndex = 0;
184
+ function push7(value_) {
185
+ let bits = (value_ & 0b01111111) << 1;
186
+ current |= bits >>> bitIndex;
187
+ bitIndex += 7;
188
+ if (bitIndex < 8)
189
+ return;
190
+ out.push(current & 0xff);
191
+ bitIndex -= 8;
192
+ bits = (bits << (7 - bitIndex)) & 0xff;
193
+ current = bits;
194
+ }
195
+ for (let i = 0; i < base122_.length; i++) {
196
+ const code = base122_.charCodeAt(i);
197
+ if (code <= 0x7f) {
198
+ push7(code);
199
+ continue;
200
+ }
201
+ const illegalIndex = (code >>> 8) & 0b111;
202
+ if (illegalIndex < BASE122_ILLEGAL.length)
203
+ push7(BASE122_ILLEGAL[illegalIndex]);
204
+ else if (illegalIndex !== BASE122_SHORT)
205
+ throw new InsErr(`Invalid base-122 illegal index ${illegalIndex} at position ${i}`);
206
+ push7(code & 0b01111111);
207
+ }
208
+ return Uint8Array.from(out);
209
+ }
package/dist/dom.d.ts ADDED
@@ -0,0 +1,69 @@
1
+ import * as bs from "./base.ts";
2
+ /**
3
+ * Subclass of {@link bs.InsErr} that represents an error thrown from this specific module of the library
4
+ */
5
+ export declare class DomErr extends bs.InsErr {
6
+ name: string;
7
+ }
8
+ /**
9
+ * Returns a Promise that resolves when the DOM is fully loaded and ready.
10
+ *
11
+ * @returns A Promise that resolves when the DOM is ready.
12
+ */
13
+ export declare function onceReady(): Promise<void>;
14
+ /**
15
+ * Retrieves an HTML element by its ID and ensures it matches the specified type.
16
+ *
17
+ * @param id_ - The ID of the HTML element to retrieve.
18
+ * @param elementType_ - An optional constructor function for the expected element type.
19
+ * @returns The HTML element with the specified ID and type.
20
+ * @throws Will throw an error if the element is not found or does not match the expected type.
21
+ */
22
+ export declare function byId<T extends HTMLElement>(id_: string, elementType_?: new () => T): T;
23
+ /**
24
+ * Retrieves all HTML elements with the specified class name and ensures they match the specified type.
25
+ *
26
+ * @param className_ - The class name of the elements to retrieve.
27
+ * @param elementType_ - An optional constructor function for the expected element type.
28
+ * @returns An array of {@link HTMLElement} with the specified class name and type.
29
+ * @throws Will throw an error if any element does not match the expected type.
30
+ */
31
+ export declare function byClass<T extends HTMLElement>(className_: string, elementType_?: new () => T): T[];
32
+ /**
33
+ * Retrieves all HTML elements with the specified tag name.
34
+ *
35
+ * @param tagName_ - The tag name of the HTML elements to retrieve.
36
+ */
37
+ export declare function byTag<K extends keyof HTMLElementTagNameMap>(tagName_: K): HTMLElementTagNameMap[K][];
38
+ /**
39
+ * Regular expression to match cookie name-value pairs in a cookie string.
40
+ */
41
+ export declare const COOKIE_PAIR_REGEX: RegExp;
42
+ /**
43
+ * Sets a cookie with the specified name, data, and optional path.
44
+ *
45
+ * @param name_ - The name of the cookie.
46
+ * @param data_ - The data to be stored in the cookie, including its value and optional attributes.
47
+ * @param path_ - An optional path for the cookie; defaults to {@link DEFAULT_PATH}.
48
+ */
49
+ export declare function setCookie(name_: string, data_: {
50
+ value: unknown;
51
+ expires?: Date | number;
52
+ domain?: string;
53
+ secure?: boolean;
54
+ sameSite?: 'Strict' | 'Lax' | 'None';
55
+ }, path_?: string): void;
56
+ /**
57
+ * Expires a cookie by setting its value to an empty string and its expiration date to the Unix epoch.
58
+ *
59
+ * @param name_ - The name of the cookie to expire.
60
+ * @param path_ - An optional path for the cookie; defaults to {@link DEFAULT_PATH}.
61
+ */
62
+ export declare function expireCookie(name_: string, path_?: string): void;
63
+ /**
64
+ * Lists all cookies as a record of name-value pairs.
65
+ *
66
+ * @returns A record where each key is a cookie name and each value is the corresponding cookie value.
67
+ */
68
+ export declare function cookies(): Record<string, unknown>;
69
+ //# sourceMappingURL=dom.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dom.d.ts","sourceRoot":"","sources":["../src/dom.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,WAAW,CAAA;AAC/B;;GAEG;AACH,qBAAa,MAAO,SAAQ,EAAE,CAAC,MAAM;IAAY,IAAI,SAA8B;CAAE;AAIrF;;;;GAIG;AACH,wBAAsB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAI/C;AAID;;;;;;;GAOG;AACH,wBAAgB,IAAI,CAAC,CAAC,SAAS,WAAW,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,UAAU,CAAC,GAAG,CAAC,CAMtF;AAGD;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,CAAC,SAAS,WAAW,EAAE,UAAU,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,UAAU,CAAC,GAAG,CAAC,EAAE,CAOlG;AAGD;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,CAAC,SAAS,MAAM,qBAAqB,EAAE,QAAQ,EAAE,CAAC,GAAG,qBAAqB,CAAC,CAAC,CAAC,EAAE,CAEpG;AAID;;GAEG;AACH,eAAO,MAAM,iBAAiB,QAA8B,CAAA;AAI5D;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE;IAC9C,KAAK,EAAE,OAAO,CAAA;IACd,OAAO,CAAC,EAAE,IAAI,GAAG,MAAM,CAAA;IACvB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,QAAQ,CAAC,EAAE,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAA;CACrC,EAAE,KAAK,SAAM,GAAG,IAAI,CASpB;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,SAAM,GAAG,IAAI,CAE7D;AAED;;;;GAIG;AACH,wBAAgB,OAAO,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAMjD"}
package/dist/dom.js ADDED
@@ -0,0 +1,103 @@
1
+ import * as bs from "./base.js";
2
+ /**
3
+ * Subclass of {@link bs.InsErr} that represents an error thrown from this specific module of the library
4
+ */
5
+ export class DomErr extends bs.InsErr {
6
+ name = "Instrumentality-DOM-Error";
7
+ }
8
+ /**
9
+ * Returns a Promise that resolves when the DOM is fully loaded and ready.
10
+ *
11
+ * @returns A Promise that resolves when the DOM is ready.
12
+ */
13
+ export async function onceReady() {
14
+ if (document.readyState === "complete" || document.readyState === "interactive")
15
+ return Promise.resolve();
16
+ return new Promise(r => document.addEventListener("DOMContentLoaded", () => r(), { once: true }));
17
+ }
18
+ /**
19
+ * Retrieves an HTML element by its ID and ensures it matches the specified type.
20
+ *
21
+ * @param id_ - The ID of the HTML element to retrieve.
22
+ * @param elementType_ - An optional constructor function for the expected element type.
23
+ * @returns The HTML element with the specified ID and type.
24
+ * @throws Will throw an error if the element is not found or does not match the expected type.
25
+ */
26
+ export function byId(id_, elementType_) {
27
+ const element = document.getElementById(id_);
28
+ const typeCtor = elementType_ ?? HTMLElement;
29
+ if (!(element instanceof typeCtor))
30
+ throw new DomErr(`Type missmatch: Element with id '${id_}' is not of type ${typeCtor.name}`);
31
+ return element;
32
+ }
33
+ /**
34
+ * Retrieves all HTML elements with the specified class name and ensures they match the specified type.
35
+ *
36
+ * @param className_ - The class name of the elements to retrieve.
37
+ * @param elementType_ - An optional constructor function for the expected element type.
38
+ * @returns An array of {@link HTMLElement} with the specified class name and type.
39
+ * @throws Will throw an error if any element does not match the expected type.
40
+ */
41
+ export function byClass(className_, elementType_) {
42
+ return Array.from(document.getElementsByClassName(className_)).map((element, index) => {
43
+ const typeCtor = elementType_ ?? HTMLElement;
44
+ if (!(element instanceof typeCtor))
45
+ throw new DomErr(`Type missmatch: Element at index ${index} with class '${className_}' is not of type ${typeCtor.name}`);
46
+ return element;
47
+ });
48
+ }
49
+ /**
50
+ * Retrieves all HTML elements with the specified tag name.
51
+ *
52
+ * @param tagName_ - The tag name of the HTML elements to retrieve.
53
+ */
54
+ export function byTag(tagName_) {
55
+ return Array.from(document.getElementsByTagName(tagName_));
56
+ }
57
+ /**
58
+ * Regular expression to match cookie name-value pairs in a cookie string.
59
+ */
60
+ export const COOKIE_PAIR_REGEX = /(?:^|; )([^=;]+)=([^;]*)/g;
61
+ /**
62
+ * Sets a cookie with the specified name, data, and optional path.
63
+ *
64
+ * @param name_ - The name of the cookie.
65
+ * @param data_ - The data to be stored in the cookie, including its value and optional attributes.
66
+ * @param path_ - An optional path for the cookie; defaults to {@link DEFAULT_PATH}.
67
+ */
68
+ export function setCookie(name_, data_, path_ = '/') {
69
+ let cookieString = `${encodeURIComponent(name_)}=${encodeURIComponent(JSON.stringify(data_.value))}; Path=${path_}`;
70
+ if (data_.expires)
71
+ if (data_.expires instanceof Date)
72
+ cookieString += `; Expires=${data_.expires.toUTCString()}`;
73
+ else
74
+ cookieString += `; Max-Age=${data_.expires}`;
75
+ if (data_.domain)
76
+ cookieString += `; Domain=${data_.domain}`;
77
+ if (data_.secure)
78
+ cookieString += `; Secure`;
79
+ if (data_.sameSite)
80
+ cookieString += `; SameSite=${data_.sameSite}`;
81
+ document.cookie = cookieString;
82
+ }
83
+ /**
84
+ * Expires a cookie by setting its value to an empty string and its expiration date to the Unix epoch.
85
+ *
86
+ * @param name_ - The name of the cookie to expire.
87
+ * @param path_ - An optional path for the cookie; defaults to {@link DEFAULT_PATH}.
88
+ */
89
+ export function expireCookie(name_, path_ = '/') {
90
+ setCookie(name_, { value: "", expires: new Date(0) }, path_);
91
+ }
92
+ /**
93
+ * Lists all cookies as a record of name-value pairs.
94
+ *
95
+ * @returns A record where each key is a cookie name and each value is the corresponding cookie value.
96
+ */
97
+ export function cookies() {
98
+ const cookies = {};
99
+ const matches = document.cookie.matchAll(COOKIE_PAIR_REGEX);
100
+ for (const match of matches)
101
+ cookies[decodeURIComponent(match[1] ?? "")] = JSON.parse(decodeURIComponent(match[2] ?? ""));
102
+ return cookies;
103
+ }