instrumentality 0.0.3 → 0.0.4

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/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "url": "https://github.com/clerkburk/instrumentality.git"
6
6
  },
7
7
  "type": "module",
8
- "version": "0.0.3",
8
+ "version": "0.0.4",
9
9
  "main": "./dist/base.js",
10
10
  "types": "./dist/base.d.ts",
11
11
  "devDependencies": {
package/src/base.ts CHANGED
@@ -1,6 +1,4 @@
1
- /**
2
- * Subclass of {@link Error} that represents an error thrown from this library, providing a specific name for easier identification.
3
- */
1
+ /** Subclass of {@link Error} that represents an error thrown from this library, providing a specific name for easier identification. */
4
2
  export class InsErr extends Error { override name = "Instrumentality-Error" }
5
3
 
6
4
 
@@ -11,22 +9,23 @@ export class InsErr extends Error { override name = "Instrumentality-Error" }
11
9
  *
12
10
  * @param fn_ - The function to be retried.
13
11
  * @param maxAttempts_ - The maximum number of attempts to execute the function.
14
- * @param _cbErr - An optional callback function to be executed after each failed attempt.
12
+ * @param cbErr_ - An optional callback function to be executed after each failed attempt.
15
13
  * @param abs_ - An optional AbortSignal to abort the retry process.
16
- * @returns The result of the function if it succeeds within the allowed attempts.
17
- * @throws If the maximum number of attempts is exceeded or if the operation is aborted.
14
+ * @returns The result of {@link fn_} if it succeeds within the allowed attempts.
15
+ * @throws {unknown} If {@link fn_} fails after the maximum attempts, the last error thrown by {@link fn_} is re-thrown.
16
+ * @throws {InsErr} If the maximum attempts is less than 1 or if the operation is aborted.
18
17
  */
19
- export async function retry<T>(fn_: () => T, maxAttempts_: number, _cbErr?: () => unknown, abs_?: AbortSignal): Promise<T> {
18
+ export async function retry<T>(fn_: () => T, maxAttempts_: number, cbErr_?: () => unknown, abs_?: AbortSignal): Promise<T> {
20
19
  while (--maxAttempts_ >= 0 && !(abs_?.aborted ?? false))
21
20
  try {
22
21
  return await fn_()
23
22
  } catch (err: unknown) {
24
- if (maxAttempts_ === 0)
23
+ if (maxAttempts_ <= 0)
25
24
  throw err
26
- await _cbErr?.()
25
+ await cbErr_?.()
27
26
  }
28
27
  if (maxAttempts_ < 0)
29
- throw new InsErr("Max attempts exceeded")
28
+ throw new InsErr("Max attempts must be at least 1")
30
29
  else
31
30
  throw new InsErr("Operation aborted")
32
31
  }
@@ -34,11 +33,11 @@ export async function retry<T>(fn_: () => T, maxAttempts_: number, _cbErr?: () =
34
33
 
35
34
 
36
35
  /**
37
- * Asynchronously sleeps for a specified duration, with optional abort signal support.
36
+ * Asynchronously sleep.
38
37
  *
39
38
  * @param ms_ - The number of milliseconds to sleep.
40
39
  * @param abs_ - An optional AbortSignal to abort the sleep.
41
- * @returns A Promise that resolves after the specified duration or rejects if aborted.
40
+ * @throws {InsErr} If the sleep is aborted before or during the wait.
42
41
  */
43
42
  export async function sleep(ms_: number, abs_?: AbortSignal): Promise<void> {
44
43
  if (abs_?.aborted)
@@ -61,7 +60,7 @@ export async function sleep(ms_: number, abs_?: AbortSignal): Promise<void> {
61
60
 
62
61
 
63
62
  /**
64
- * Helper type to build a tuple of a specified length.
63
+ * Build a tuple of a specified length.
65
64
  *
66
65
  * @template N - The desired length of the tuple.
67
66
  * @template T - The tuple being built (used for recursion).
@@ -71,7 +70,7 @@ type BuildTuple<N extends number, T extends number[] = []> =
71
70
 
72
71
 
73
72
  /**
74
- * Helper type to add two number types together.
73
+ * Add two number types together.
75
74
  *
76
75
  * @template A - The first number type.
77
76
  * @template B - The second number type.
@@ -81,7 +80,7 @@ export type Add<A extends number, B extends number> =
81
80
 
82
81
 
83
82
  /**
84
- * Helper type to enumerate numbers from 0 to N-1.
83
+ * Enumerate numbers from 0 to N-1 as a union type.
85
84
  *
86
85
  * @template N - The upper limit (exclusive) for the enumeration.
87
86
  * @template A - The accumulator array used for recursion.
@@ -92,31 +91,28 @@ A['length'] extends N ? A[number] : Enumerate<N, [...A, A['length']]>
92
91
 
93
92
 
94
93
  /**
95
- * A benchmarking class that provides various time units for measuring elapsed time.
96
- *
97
- * The class starts a timer upon instantiation and provides properties to access the elapsed time in different units (milliseconds, seconds, minutes, etc.).
98
- * The `round` method can be called to record the current elapsed time and restart the timer.
94
+ * Wrapper around {@link performance.now}
99
95
  *
100
96
  * @property {@link rounds} - An array that stores the recorded elapsed times from each round.
101
97
  * @property {@link timer} - The initial timestamp when the benchmark was created or last reset.
102
98
  * @method {@link round} - Records the current elapsed time and restarts the timer.
103
99
  * @method {@link reset} - Resets the benchmark timer to the current time and clears recorded rounds.
104
- * @accessor {@link y} - Elapsed time in years.
105
- * @accessor {@link mn} - Elapsed time in months.
106
- * @accessor {@link w} - Elapsed time in weeks.
107
- * @accessor {@link d} - Elapsed time in days.
108
- * @accessor {@link h} - Elapsed time in hours.
109
- * @accessor {@link m} - Elapsed time in minutes.
110
- * @accessor {@link s} - Elapsed time in seconds.
111
- * @accessor {@link ms} - Elapsed time in milliseconds.
112
- * @accessor {@link μs} - Elapsed time in microseconds.
113
- * @accessor {@link ns} - Elapsed time in nanoseconds.
114
- * @accessor {@link ps} - Elapsed time in picoseconds.
100
+ * @accessor {@link y} (years)
101
+ * @accessor {@link mn} (months)
102
+ * @accessor {@link w} (weeks)
103
+ * @accessor {@link d} (days)
104
+ * @accessor {@link h} (hours)
105
+ * @accessor {@link m} (minutes)
106
+ * @accessor {@link s} (seconds)
107
+ * @accessor {@link ms} (milliseconds)
108
+ * @accessor {@link μs} (microseconds)
109
+ * @accessor {@link ns} (nanoseconds)
110
+ * @accessor {@link ps} (picoseconds)
115
111
  */
116
112
  export class Benchmark {
117
- /** An array that stores the recorded elapsed times from each round. */
113
+ /** An array that stores the recorded elapsed times from each round (relative to the previous). */
118
114
  rounds: number[] = []
119
- /** Initializes the benchmark timer to the current time using `performance.now()`. */
115
+ /** The initial timestamp when the benchmark was created or last reset. */
120
116
  timer = performance.now()
121
117
  /** Records the current elapsed time and restarts the timer. */
122
118
  round() { this.rounds.push(this.ms); this.timer = performance.now() }
@@ -149,9 +145,7 @@ export { Benchmark as Bench, Benchmark as Timer, Benchmark as Stopwatch }
149
145
 
150
146
 
151
147
 
152
- /**
153
- * Helper type that represents a view of a Uint8Array, exposing only view methods and properties, along with a readonly index signature for accessing elements.
154
- */
148
+ /** Compiler sugar to hide mutating methods/properties for read-only operations (no runtime effect). */
155
149
  export type Uint8ArrayView = Pick<Uint8Array,
156
150
  | "at"
157
151
  | "includes"
@@ -202,22 +196,13 @@ export const BASE122_SHORT = 0b111 as const
202
196
 
203
197
 
204
198
  /**
205
- * Encodes indexed data into a base-122 representation, going as low as 14% overhead for regular data, making base-64 look pathetic in comparison with its 33% overhead.
206
- * 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.
199
+ * Encodes indexed data into a base-122 representation.
207
200
  *
208
- * @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.
209
201
  * @param data_ - An array-like object containing the data to be encoded.
210
202
  * @returns A string representing the base-122 encoded data.
211
- * @throws If somehow malformed UTF-8 data is generated, the TextDecoder will throw an error (shouldn't happen if the input is valid).
212
- * @see {@link decode122} for decoding the base-122 string back into its original byte representation.
213
- * @see {@link BASE122_ILLEGAL} for the list of reserved characters that are escaped during encoding.
214
- * @example
215
- * // (pseudo-code)
216
- * // build script
217
- * appendFile(".html", `<script type="text/plain">${encode122(compress(readFile(".jpg")))}</script>`)
218
- *
219
- * // HTML
220
- * <script type="text/plain">!!pƋƸ€€²VӦnKZ6w )jpA</script> // embedd data into HTML without it being interpreted as HTML or JS
203
+ * @throws If somehow malformed UTF-8 data is generated, the {@link TextDecoder} will throw an error (shouldn't happen if the input is valid).
204
+ * @remarks The high density might not be suitable for all use cases, especially if the medium used to transmit the data has limitations on character sets or encoding.
205
+ * @see {@link TextDecoder} how the output string is generated from the byte array (this step is necessary for accurate translation to a string).
221
206
  */
222
207
  export function encode122(data_: ArrayLike<number>): string {
223
208
  const out: number[] = []
@@ -259,12 +244,10 @@ export function encode122(data_: ArrayLike<number>): string {
259
244
 
260
245
  /**
261
246
  * Decodes a base-122 encoded string back into its original byte representation.
262
- * The decoding process reverses the encoding, extracting 7 bits of data from each character and handling two-byte sequences for illegal characters.
263
247
  *
264
248
  * @param base122_ - The base-122 encoded string to decode.
265
249
  * @returns A Uint8Array containing the original byte data.
266
250
  * @throws If an invalid base-122 illegal index is encountered during decoding (shouldn't happen if the input was generated by {@link encode122}).
267
- * @see {@link encode122} for encoding data into base-122.
268
251
  */
269
252
  export function decode122(base122_: string) {
270
253
  const out: number[] = []
package/src/dom.ts CHANGED
@@ -1,82 +1,67 @@
1
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
- */
2
+
3
+
4
+
5
+ /** Subclass of {@link bs.InsErr} that represents an error thrown from this specific module of the library */
5
6
  export class DomErr extends bs.InsErr { override name = "Instrumentality-DOM-Error" }
6
7
 
7
8
 
8
9
 
9
10
  /**
10
- * Returns a Promise that resolves when the DOM is fully loaded and ready.
11
- *
12
- * @returns A Promise that resolves when the DOM is ready.
11
+ * Resolves on `DOMContentLoaded` or immediately if the document is already ready.
13
12
  */
14
13
  export async function onceReady(): Promise<void> {
15
14
  if (document.readyState === "complete" || document.readyState === "interactive")
16
- return Promise.resolve()
15
+ return
17
16
  return new Promise(r => document.addEventListener("DOMContentLoaded", () => r(), { once: true }))
18
17
  }
19
18
 
20
19
 
21
20
 
22
21
  /**
23
- * Retrieves an HTML element by its ID and ensures it matches the specified type.
22
+ * Typed accessor for {@link document.getElementById}
24
23
  *
25
- * @param id_ - The ID of the HTML element to retrieve.
26
- * @param elementType_ - An optional constructor function for the expected element type.
27
- * @returns The HTML element with the specified ID and type.
28
- * @throws Will throw an error if the element is not found or does not match the expected type.
24
+ * @param id_ - The ID of the element to retrieve.
25
+ * @param type_ - Expected type, defaults to {@link HTMLElement}.
26
+ * @returns The corresponding element if found and of the expected type, otherwise `null`.
29
27
  */
30
- export function byId<T extends HTMLElement>(id_: string, elementType_?: new () => T): T {
28
+ export function byId<T extends HTMLElement>(id_: string, type_: new () => T): T | null {
31
29
  const element = document.getElementById(id_)
32
- const typeCtor = elementType_ ?? HTMLElement
33
- if (!(element instanceof typeCtor))
34
- throw new DomErr(`Type missmatch: Element with id '${id_}' is not of type ${typeCtor.name}`)
35
- return element as T
30
+ if (element instanceof type_)
31
+ return element
32
+ return null
36
33
  }
37
34
 
38
35
 
39
36
  /**
40
- * Retrieves all HTML elements with the specified class name and ensures they match the specified type.
37
+ * Typed accessor for {@link document.getElementsByClassName}
41
38
  *
42
39
  * @param className_ - The class name of the elements to retrieve.
43
- * @param elementType_ - An optional constructor function for the expected element type.
44
- * @returns An array of {@link HTMLElement} with the specified class name and type.
45
- * @throws Will throw an error if any element does not match the expected type.
40
+ * @param type_ - An optional constructor function for the expected element type.
41
+ * @returns All elements with the specified class name and type.
46
42
  */
47
- export function byClass<T extends HTMLElement>(className_: string, elementType_?: new () => T): T[] {
48
- return Array.from(document.getElementsByClassName(className_)).map((element, index) => {
49
- const typeCtor = elementType_ ?? HTMLElement
50
- if (!(element instanceof typeCtor))
51
- throw new DomErr(`Type missmatch: Element at index ${index} with class '${className_}' is not of type ${typeCtor.name}`)
52
- return element as T
53
- })
43
+ export function byClass<T extends HTMLElement>(className_: string, type_: new () => T): T[] {
44
+ return [...document.getElementsByClassName(className_)].filter((el): el is T => el instanceof type_)
54
45
  }
55
46
 
56
47
 
57
48
  /**
58
- * Retrieves all HTML elements with the specified tag name.
49
+ * Typed accessor for {@link document.getElementsByTagName}
59
50
  *
60
- * @param tagName_ - The tag name of the HTML elements to retrieve.
51
+ * @param tag_ - The HTML tag name of the elements to retrieve.
52
+ * @returns An array of {@link HTMLElement}s with the specified tag name.
61
53
  */
62
- export function byTag<K extends keyof HTMLElementTagNameMap>(tagName_: K): HTMLElementTagNameMap[K][] {
63
- return Array.from(document.getElementsByTagName(tagName_))
54
+ export function byTag<K extends keyof HTMLElementTagNameMap>(tag_: K): HTMLElementTagNameMap[K][] {
55
+ return [...document.getElementsByTagName(tag_)]
64
56
  }
65
57
 
66
58
 
67
59
 
68
- /**
69
- * Regular expression to match cookie name-value pairs in a cookie string.
70
- */
71
- export const COOKIE_PAIR_REGEX = /(?:^|; )([^=;]+)=([^;]*)/g
72
-
73
-
74
-
75
60
  /**
76
61
  * Sets a cookie with the specified name, data, and optional path.
77
62
  *
78
63
  * @param name_ - The name of the cookie.
79
- * @param data_ - The data to be stored in the cookie, including its value and optional attributes.
64
+ * @param data_ - The data to be stored in the cookie.
80
65
  * @param path_ - An optional path for the cookie; defaults to {@link DEFAULT_PATH}.
81
66
  */
82
67
  export function setCookie(name_: string, data_: {
@@ -97,9 +82,9 @@ export function setCookie(name_: string, data_: {
97
82
  }
98
83
 
99
84
  /**
100
- * Expires a cookie by setting its value to an empty string and its expiration date to the Unix epoch.
85
+ * Expires a cookie immediately.
101
86
  *
102
- * @param name_ - The name of the cookie to expire.
87
+ * @param name_ - The name of the cookie.
103
88
  * @param path_ - An optional path for the cookie; defaults to {@link DEFAULT_PATH}.
104
89
  */
105
90
  export function expireCookie(name_: string, path_ = '/'): void {
@@ -107,13 +92,13 @@ export function expireCookie(name_: string, path_ = '/'): void {
107
92
  }
108
93
 
109
94
  /**
110
- * Lists all cookies as a record of name-value pairs.
95
+ * Lists all cookies as a record of key-value pairs.
111
96
  *
112
97
  * @returns A record where each key is a cookie name and each value is the corresponding cookie value.
113
98
  */
114
99
  export function cookies(): Record<string, unknown> {
115
100
  const cookies: Record<string, unknown> = {}
116
- const matches = document.cookie.matchAll(COOKIE_PAIR_REGEX)
101
+ const matches = document.cookie.matchAll(/(?:^|; )([^=;]+)=([^;]*)/g)
117
102
  for (const match of matches)
118
103
  cookies[decodeURIComponent(match[1] ?? "")] = JSON.parse(decodeURIComponent(match[2] ?? ""))
119
104
  return cookies