@fuzdev/fuz_util 0.42.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.
Files changed (135) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +83 -0
  3. package/dist/array.d.ts +15 -0
  4. package/dist/array.d.ts.map +1 -0
  5. package/dist/array.js +25 -0
  6. package/dist/async.d.ts +62 -0
  7. package/dist/async.d.ts.map +1 -0
  8. package/dist/async.js +147 -0
  9. package/dist/colors.d.ts +41 -0
  10. package/dist/colors.d.ts.map +1 -0
  11. package/dist/colors.js +106 -0
  12. package/dist/counter.d.ts +7 -0
  13. package/dist/counter.d.ts.map +1 -0
  14. package/dist/counter.js +7 -0
  15. package/dist/deep_equal.d.ts +18 -0
  16. package/dist/deep_equal.d.ts.map +1 -0
  17. package/dist/deep_equal.js +152 -0
  18. package/dist/dom.d.ts +35 -0
  19. package/dist/dom.d.ts.map +1 -0
  20. package/dist/dom.js +95 -0
  21. package/dist/error.d.ts +15 -0
  22. package/dist/error.d.ts.map +1 -0
  23. package/dist/error.js +18 -0
  24. package/dist/fetch.d.ts +81 -0
  25. package/dist/fetch.d.ts.map +1 -0
  26. package/dist/fetch.js +162 -0
  27. package/dist/fs.d.ts +34 -0
  28. package/dist/fs.d.ts.map +1 -0
  29. package/dist/fs.js +73 -0
  30. package/dist/function.d.ts +27 -0
  31. package/dist/function.d.ts.map +1 -0
  32. package/dist/function.js +21 -0
  33. package/dist/git.d.ts +132 -0
  34. package/dist/git.d.ts.map +1 -0
  35. package/dist/git.js +288 -0
  36. package/dist/id.d.ts +18 -0
  37. package/dist/id.d.ts.map +1 -0
  38. package/dist/id.js +18 -0
  39. package/dist/iterator.d.ts +5 -0
  40. package/dist/iterator.d.ts.map +1 -0
  41. package/dist/iterator.js +9 -0
  42. package/dist/json.d.ts +30 -0
  43. package/dist/json.d.ts.map +1 -0
  44. package/dist/json.js +44 -0
  45. package/dist/library_json.d.ts +42 -0
  46. package/dist/library_json.d.ts.map +1 -0
  47. package/dist/library_json.js +76 -0
  48. package/dist/log.d.ts +188 -0
  49. package/dist/log.d.ts.map +1 -0
  50. package/dist/log.js +393 -0
  51. package/dist/map.d.ts +12 -0
  52. package/dist/map.d.ts.map +1 -0
  53. package/dist/map.js +14 -0
  54. package/dist/maths.d.ts +85 -0
  55. package/dist/maths.d.ts.map +1 -0
  56. package/dist/maths.js +87 -0
  57. package/dist/object.d.ts +46 -0
  58. package/dist/object.d.ts.map +1 -0
  59. package/dist/object.js +89 -0
  60. package/dist/package_json.d.ts +90 -0
  61. package/dist/package_json.d.ts.map +1 -0
  62. package/dist/package_json.js +112 -0
  63. package/dist/path.d.ts +63 -0
  64. package/dist/path.d.ts.map +1 -0
  65. package/dist/path.js +83 -0
  66. package/dist/print.d.ts +52 -0
  67. package/dist/print.d.ts.map +1 -0
  68. package/dist/print.js +89 -0
  69. package/dist/process.d.ts +77 -0
  70. package/dist/process.d.ts.map +1 -0
  71. package/dist/process.js +148 -0
  72. package/dist/random.d.ts +25 -0
  73. package/dist/random.d.ts.map +1 -0
  74. package/dist/random.js +35 -0
  75. package/dist/random_alea.d.ts +23 -0
  76. package/dist/random_alea.d.ts.map +1 -0
  77. package/dist/random_alea.js +95 -0
  78. package/dist/regexp.d.ts +12 -0
  79. package/dist/regexp.d.ts.map +1 -0
  80. package/dist/regexp.js +16 -0
  81. package/dist/result.d.ts +64 -0
  82. package/dist/result.d.ts.map +1 -0
  83. package/dist/result.js +48 -0
  84. package/dist/source_json.d.ts +375 -0
  85. package/dist/source_json.d.ts.map +1 -0
  86. package/dist/source_json.js +189 -0
  87. package/dist/string.d.ts +51 -0
  88. package/dist/string.d.ts.map +1 -0
  89. package/dist/string.js +92 -0
  90. package/dist/throttle.d.ts +26 -0
  91. package/dist/throttle.d.ts.map +1 -0
  92. package/dist/throttle.js +53 -0
  93. package/dist/timings.d.ts +33 -0
  94. package/dist/timings.d.ts.map +1 -0
  95. package/dist/timings.js +75 -0
  96. package/dist/types.d.ts +77 -0
  97. package/dist/types.d.ts.map +1 -0
  98. package/dist/types.js +10 -0
  99. package/dist/url.d.ts +10 -0
  100. package/dist/url.d.ts.map +1 -0
  101. package/dist/url.js +8 -0
  102. package/package.json +125 -0
  103. package/src/lib/array.ts +30 -0
  104. package/src/lib/async.ts +182 -0
  105. package/src/lib/colors.ts +132 -0
  106. package/src/lib/counter.ts +11 -0
  107. package/src/lib/deep_equal.ts +155 -0
  108. package/src/lib/dom.ts +108 -0
  109. package/src/lib/error.ts +22 -0
  110. package/src/lib/fetch.ts +231 -0
  111. package/src/lib/fs.ts +128 -0
  112. package/src/lib/function.ts +32 -0
  113. package/src/lib/git.ts +390 -0
  114. package/src/lib/id.ts +30 -0
  115. package/src/lib/iterator.ts +8 -0
  116. package/src/lib/json.ts +61 -0
  117. package/src/lib/library_json.ts +122 -0
  118. package/src/lib/log.ts +469 -0
  119. package/src/lib/map.ts +18 -0
  120. package/src/lib/maths.ts +91 -0
  121. package/src/lib/object.ts +110 -0
  122. package/src/lib/package_json.ts +135 -0
  123. package/src/lib/path.ts +137 -0
  124. package/src/lib/print.ts +111 -0
  125. package/src/lib/process.ts +207 -0
  126. package/src/lib/random.ts +48 -0
  127. package/src/lib/random_alea.ts +107 -0
  128. package/src/lib/regexp.ts +17 -0
  129. package/src/lib/result.ts +67 -0
  130. package/src/lib/source_json.ts +209 -0
  131. package/src/lib/string.ts +99 -0
  132. package/src/lib/throttle.ts +70 -0
  133. package/src/lib/timings.ts +93 -0
  134. package/src/lib/types.ts +99 -0
  135. package/src/lib/url.ts +14 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) Ryan Atkinson <mail@ryanatkn.com> <https://ryanatkn.com/>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,83 @@
1
+ # @ryanatkn/belt
2
+
3
+ [<img src="static/logo.svg" alt="a green sauropod wearing a brown utility belt" align="right" width="256" height="256">](https://belt.ryanatkn.com/)
4
+
5
+ > utility belt for JS 🦕 ancient not extinct
6
+
7
+ **[belt.ryanatkn.com](https://belt.ryanatkn.com)**
8
+
9
+ design:
10
+
11
+ - kitchen-sink utilities library - sorry, I wish it weren't so, JS made me do it
12
+ - two optional runtime dependencies on [`zod`](https://github.com/colinhacks/zod)
13
+ and [`esm-env`](https://github.com/benmccann/esm-env),
14
+ one optional type dependency on `@types/node`
15
+ - mix of JS module environments - browser-only, Node-only, universal
16
+ - mostly small pure functions
17
+ - all TypeScript, for styles and Svelte and SvelteKit
18
+ see <a href="https://github.com/fuz-dev/fuz">@ryanatkn/fuz</a>
19
+ - complements the modern web platform, drops legacy quickly
20
+ - kinda minimal in many ways but also not, treeshakes well
21
+
22
+ ## usage
23
+
24
+ Install from [npm](https://www.npmjs.com/package/@ryanatkn/belt):
25
+
26
+ ```bash
27
+ npm i -D @ryanatkn/belt
28
+ ```
29
+
30
+ Import modules at their full paths:
31
+
32
+ ```ts
33
+ import {type Result, unwrap} from '@ryanatkn/belt/result.js';
34
+ import {random_int} from '@ryanatkn/belt/random.js';
35
+ ```
36
+
37
+ `.ts` imports also work:
38
+
39
+ ```ts
40
+ import {deep_equal} from '@ryanatkn/belt/deep_equal.ts';
41
+ ```
42
+
43
+ Docs at [belt.ryanatkn.com/docs](https://belt.ryanatkn.com/docs).
44
+
45
+ ## build
46
+
47
+ ```bash
48
+ npm run build
49
+ # or
50
+ gro build
51
+ ```
52
+
53
+ ## test
54
+
55
+ For more see [`uvu`](https://github.com/lukeed/uvu)
56
+ and [Gro's test docs](https://github.com/feltjs/gro/blob/main/src/docs/test.md).
57
+
58
+ ```bash
59
+ gro test
60
+ gro test filepattern1 filepatternB
61
+ gro test -- uvu --forwarded_args 'to uvu'
62
+ ```
63
+
64
+ ## deploy
65
+
66
+ [Deploy](https://github.com/feltjs/gro/blob/main/src/docs/deploy.md)
67
+ (build, commit, and push) to the `deploy` branch, e.g. for GitHub Pages:
68
+
69
+ ```bash
70
+ npm run deploy
71
+ # or
72
+ gro deploy
73
+ ```
74
+
75
+ ## credits 🐢<sub>🐢</sub><sub><sub>🐢</sub></sub>
76
+
77
+ My sister Lisa helped me with the logo -
78
+ [instagram.com/lisaeatkinson](https://www.instagram.com/lisaeatkinson/) -
79
+ she's a designer and currently looking for work
80
+
81
+ ## license [🐦](https://wikipedia.org/wiki/Free_and_open-source_software)
82
+
83
+ [MIT](LICENSE)
@@ -0,0 +1,15 @@
1
+ import type { ArrayElement } from './types.js';
2
+ export declare const EMPTY_ARRAY: Array<any>;
3
+ /** Converts `value` to an array if it's not already. */
4
+ export declare const to_array: <T>(value: T) => T extends ReadonlyArray<any> ? T : Array<T>;
5
+ /**
6
+ * Removes an element from `array` at `index` in an unordered manner.
7
+ * @mutates array swaps element at index with last element, then removes last element
8
+ */
9
+ export declare const remove_unordered: (array: Array<any>, index: number) => void;
10
+ /**
11
+ * Returns a function that returns the next item in the `array`
12
+ * in a linear sequence, looping back to index 0 when it reaches the end.
13
+ */
14
+ export declare const to_next: <T extends ReadonlyArray<any>>(array: T) => (() => ArrayElement<T>);
15
+ //# sourceMappingURL=array.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"array.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/array.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,YAAY,CAAC;AAG7C,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,GAAG,CAA4B,CAAC;AAEhE,wDAAwD;AACxD,eAAO,MAAM,QAAQ,GAAI,CAAC,EAAE,OAAO,CAAC,KAAG,CAAC,SAAS,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,CACxB,CAAC;AAE1D;;;GAGG;AACH,eAAO,MAAM,gBAAgB,GAAI,OAAO,KAAK,CAAC,GAAG,CAAC,EAAE,OAAO,MAAM,KAAG,IAGnE,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,OAAO,GAAI,CAAC,SAAS,aAAa,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,KAAG,CAAC,MAAM,YAAY,CAAC,CAAC,CAAC,CAOtF,CAAC"}
package/dist/array.js ADDED
@@ -0,0 +1,25 @@
1
+ // TODO try to cange to readonly again, see if upstream errors are tolerably fixed
2
+ export const EMPTY_ARRAY = Object.freeze([]);
3
+ /** Converts `value` to an array if it's not already. */
4
+ export const to_array = (value) => Array.isArray(value) ? value : [value];
5
+ /**
6
+ * Removes an element from `array` at `index` in an unordered manner.
7
+ * @mutates array swaps element at index with last element, then removes last element
8
+ */
9
+ export const remove_unordered = (array, index) => {
10
+ array[index] = array[array.length - 1];
11
+ array.pop();
12
+ };
13
+ /**
14
+ * Returns a function that returns the next item in the `array`
15
+ * in a linear sequence, looping back to index 0 when it reaches the end.
16
+ */
17
+ export const to_next = (array) => {
18
+ let i = -1;
19
+ return () => {
20
+ i++;
21
+ if (i >= array.length)
22
+ i = 0;
23
+ return array[i];
24
+ };
25
+ };
@@ -0,0 +1,62 @@
1
+ export type AsyncStatus = 'initial' | 'pending' | 'success' | 'failure';
2
+ /**
3
+ * Waits for the given `duration` before resolving.
4
+ */
5
+ export declare const wait: (duration?: number) => Promise<void>;
6
+ /**
7
+ * Checks if `value` is a `Promise`.
8
+ */
9
+ export declare const is_promise: (value: any) => value is Promise<any>;
10
+ /**
11
+ * Creates a deferred object with a promise and its resolve/reject handlers.
12
+ */
13
+ export interface Deferred<T> {
14
+ promise: Promise<T>;
15
+ resolve: (value: T) => void;
16
+ reject: (reason: any) => void;
17
+ }
18
+ /**
19
+ * Creates a object with a `promise` and its `resolve`/`reject` handlers.
20
+ */
21
+ export declare const create_deferred: <T>() => Deferred<T>;
22
+ /**
23
+ * Maps over items with controlled concurrency, preserving input order.
24
+ *
25
+ * @param items array of items to process
26
+ * @param fn async function to apply to each item
27
+ * @param concurrency maximum number of concurrent operations
28
+ * @returns promise resolving to array of results in same order as input
29
+ *
30
+ * @example
31
+ * ```ts
32
+ * const results = await map_concurrent(
33
+ * file_paths,
34
+ * async (path) => readFile(path, 'utf8'),
35
+ * 5, // max 5 concurrent reads
36
+ * );
37
+ * ```
38
+ */
39
+ export declare const map_concurrent: <T, R>(items: Array<T>, fn: (item: T, index: number) => Promise<R>, concurrency: number) => Promise<Array<R>>;
40
+ /**
41
+ * Like `map_concurrent` but collects all results/errors instead of failing fast.
42
+ * Returns an array of settlement objects matching the `Promise.allSettled` pattern.
43
+ *
44
+ * @param items array of items to process
45
+ * @param fn async function to apply to each item
46
+ * @param concurrency maximum number of concurrent operations
47
+ * @returns promise resolving to array of `PromiseSettledResult` objects in input order
48
+ *
49
+ * @example
50
+ * ```ts
51
+ * const results = await map_concurrent_settled(urls, fetch, 5);
52
+ * for (const [i, result] of results.entries()) {
53
+ * if (result.status === 'fulfilled') {
54
+ * console.log(`${urls[i]}: ${result.value.status}`);
55
+ * } else {
56
+ * console.error(`${urls[i]}: ${result.reason}`);
57
+ * }
58
+ * }
59
+ * ```
60
+ */
61
+ export declare const map_concurrent_settled: <T, R>(items: Array<T>, fn: (item: T, index: number) => Promise<R>, concurrency: number) => Promise<Array<PromiseSettledResult<R>>>;
62
+ //# sourceMappingURL=async.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"async.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/async.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;AAExE;;GAEG;AACH,eAAO,MAAM,IAAI,GAAI,iBAAY,KAAG,OAAO,CAAC,IAAI,CACQ,CAAC;AAEzD;;GAEG;AACH,eAAO,MAAM,UAAU,GAAI,OAAO,GAAG,KAAG,KAAK,IAAI,OAAO,CAAC,GAAG,CAClB,CAAC;AAE3C;;GAEG;AACH,MAAM,WAAW,QAAQ,CAAC,CAAC;IAC1B,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IACpB,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IAC5B,MAAM,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;CAC9B;AAED;;GAEG;AACH,eAAO,MAAM,eAAe,GAAI,CAAC,OAAK,QAAQ,CAAC,CAAC,CAQ/C,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,cAAc,GAAU,CAAC,EAAE,CAAC,EACxC,OAAO,KAAK,CAAC,CAAC,CAAC,EACf,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,EAC1C,aAAa,MAAM,KACjB,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAoDlB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,sBAAsB,GAAU,CAAC,EAAE,CAAC,EAChD,OAAO,KAAK,CAAC,CAAC,CAAC,EACf,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,EAC1C,aAAa,MAAM,KACjB,OAAO,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,CA6CxC,CAAC"}
package/dist/async.js ADDED
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Waits for the given `duration` before resolving.
3
+ */
4
+ export const wait = (duration = 0) => new Promise((resolve) => setTimeout(resolve, duration));
5
+ /**
6
+ * Checks if `value` is a `Promise`.
7
+ */
8
+ export const is_promise = (value) => value && typeof value.then === 'function';
9
+ /**
10
+ * Creates a object with a `promise` and its `resolve`/`reject` handlers.
11
+ */
12
+ export const create_deferred = () => {
13
+ let resolve;
14
+ let reject;
15
+ const promise = new Promise((res, rej) => {
16
+ resolve = res;
17
+ reject = rej;
18
+ });
19
+ return { promise, resolve, reject };
20
+ };
21
+ /**
22
+ * Maps over items with controlled concurrency, preserving input order.
23
+ *
24
+ * @param items array of items to process
25
+ * @param fn async function to apply to each item
26
+ * @param concurrency maximum number of concurrent operations
27
+ * @returns promise resolving to array of results in same order as input
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * const results = await map_concurrent(
32
+ * file_paths,
33
+ * async (path) => readFile(path, 'utf8'),
34
+ * 5, // max 5 concurrent reads
35
+ * );
36
+ * ```
37
+ */
38
+ export const map_concurrent = async (items, fn, concurrency) => {
39
+ if (concurrency < 1) {
40
+ throw new Error('concurrency must be at least 1');
41
+ }
42
+ const results = new Array(items.length);
43
+ let next_index = 0;
44
+ let active_count = 0;
45
+ let rejected = false;
46
+ let reject_error;
47
+ return new Promise((resolve, reject) => {
48
+ const run_next = () => {
49
+ // Stop spawning if we've rejected
50
+ if (rejected)
51
+ return;
52
+ // Check if we're done
53
+ if (next_index >= items.length && active_count === 0) {
54
+ resolve(results);
55
+ return;
56
+ }
57
+ // Spawn workers up to concurrency limit
58
+ while (active_count < concurrency && next_index < items.length) {
59
+ const index = next_index++;
60
+ const item = items[index];
61
+ active_count++;
62
+ fn(item, index)
63
+ .then((result) => {
64
+ if (rejected)
65
+ return;
66
+ results[index] = result;
67
+ active_count--;
68
+ run_next();
69
+ })
70
+ .catch((error) => {
71
+ if (rejected)
72
+ return;
73
+ rejected = true;
74
+ reject_error = error;
75
+ reject(reject_error); // eslint-disable-line @typescript-eslint/prefer-promise-reject-errors
76
+ });
77
+ }
78
+ };
79
+ // Handle empty array
80
+ if (items.length === 0) {
81
+ resolve(results);
82
+ return;
83
+ }
84
+ run_next();
85
+ });
86
+ };
87
+ /**
88
+ * Like `map_concurrent` but collects all results/errors instead of failing fast.
89
+ * Returns an array of settlement objects matching the `Promise.allSettled` pattern.
90
+ *
91
+ * @param items array of items to process
92
+ * @param fn async function to apply to each item
93
+ * @param concurrency maximum number of concurrent operations
94
+ * @returns promise resolving to array of `PromiseSettledResult` objects in input order
95
+ *
96
+ * @example
97
+ * ```ts
98
+ * const results = await map_concurrent_settled(urls, fetch, 5);
99
+ * for (const [i, result] of results.entries()) {
100
+ * if (result.status === 'fulfilled') {
101
+ * console.log(`${urls[i]}: ${result.value.status}`);
102
+ * } else {
103
+ * console.error(`${urls[i]}: ${result.reason}`);
104
+ * }
105
+ * }
106
+ * ```
107
+ */
108
+ export const map_concurrent_settled = async (items, fn, concurrency) => {
109
+ if (concurrency < 1) {
110
+ throw new Error('concurrency must be at least 1');
111
+ }
112
+ const results = new Array(items.length);
113
+ let next_index = 0;
114
+ let active_count = 0;
115
+ return new Promise((resolve) => {
116
+ const run_next = () => {
117
+ // Check if we're done
118
+ if (next_index >= items.length && active_count === 0) {
119
+ resolve(results);
120
+ return;
121
+ }
122
+ // Spawn workers up to concurrency limit
123
+ while (active_count < concurrency && next_index < items.length) {
124
+ const index = next_index++;
125
+ const item = items[index];
126
+ active_count++;
127
+ fn(item, index)
128
+ .then((value) => {
129
+ results[index] = { status: 'fulfilled', value };
130
+ })
131
+ .catch((reason) => {
132
+ results[index] = { status: 'rejected', reason };
133
+ })
134
+ .finally(() => {
135
+ active_count--;
136
+ run_next();
137
+ });
138
+ }
139
+ };
140
+ // Handle empty array
141
+ if (items.length === 0) {
142
+ resolve(results);
143
+ return;
144
+ }
145
+ run_next();
146
+ });
147
+ };
@@ -0,0 +1,41 @@
1
+ import type { Flavored } from './types.js';
2
+ export type Hsl = readonly [Hue, Saturation, Lightness];
3
+ export type Hue = Flavored<number, 'Hue'>;
4
+ export type Saturation = Flavored<number, 'Saturation'>;
5
+ export type Lightness = Flavored<number, 'Lightness'>;
6
+ export type Rgb = readonly [Red, Green, Blue];
7
+ export type Red = Flavored<number, 'Red'>;
8
+ export type Green = Flavored<number, 'Green'>;
9
+ export type Blue = Flavored<number, 'Blue'>;
10
+ /**
11
+ * Converts an RGB color to a hex color.
12
+ */
13
+ export declare const rgb_to_hex: (r: number, g: number, b: number) => number;
14
+ /**
15
+ * Converts a hex color to an RGB color.
16
+ */
17
+ export declare const hex_to_rgb: (hex: number) => Rgb;
18
+ export declare const hex_string_to_rgb: (hex: string) => Rgb;
19
+ export declare const rgb_to_hex_string: (r: number, g: number, b: number) => string;
20
+ export declare const to_hex_component: (v: number) => string;
21
+ /**
22
+ * Converts an RGB color value to HSL. Conversion formula
23
+ * adapted from http://wikipedia.org/wiki/HSL_color_space.
24
+ * Values r/g/b are in the range [0,255] and
25
+ * returns h/s/l in the range [0,1].
26
+ */
27
+ export declare const rgb_to_hsl: (r: number, g: number, b: number) => Hsl;
28
+ /**
29
+ * Converts an HSL color value to RGB. Conversion formula
30
+ * adapted from http://wikipedia.org/wiki/HSL_color_space.
31
+ * Values h/s/l are in the range [0,1] and
32
+ * returns r/g/b in the range [0,255].
33
+ */
34
+ export declare const hsl_to_rgb: (h: Hue, s: Saturation, l: Lightness) => Rgb;
35
+ export declare const hue_to_rgb_component: (p: number, q: number, t: number) => number;
36
+ export declare const hsl_to_hex: (h: Hue, s: Saturation, l: Lightness) => number;
37
+ export declare const hsl_to_hex_string: (h: Hue, s: Saturation, l: Lightness) => string;
38
+ export declare const hsl_to_string: (h: Hue, s: Saturation, l: Lightness) => string;
39
+ export declare const hex_string_to_hsl: (hex: string) => Hsl;
40
+ export declare const parse_hsl_string: (hsl: string) => Hsl;
41
+ //# sourceMappingURL=colors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"colors.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/colors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,YAAY,CAAC;AAQzC,MAAM,MAAM,GAAG,GAAG,SAAS,CAAC,GAAG,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;AACxD,MAAM,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AAC1C,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;AACxD,MAAM,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;AAEtD,MAAM,MAAM,GAAG,GAAG,SAAS,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;AAC9C,MAAM,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AAC1C,MAAM,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAC9C,MAAM,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAE5C;;GAEG;AACH,eAAO,MAAM,UAAU,GAAI,GAAG,MAAM,EAAE,GAAG,MAAM,EAAE,GAAG,MAAM,KAAG,MAAkC,CAAC;AAEhG;;GAEG;AACH,eAAO,MAAM,UAAU,GAAI,KAAK,MAAM,KAAG,GAAuD,CAAC;AAEjG,eAAO,MAAM,iBAAiB,GAAI,KAAK,MAAM,KAAG,GAI/C,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,GAAG,MAAM,EAAE,GAAG,MAAM,EAAE,GAAG,MAAM,KAAG,MACE,CAAC;AAEvE,eAAO,MAAM,gBAAgB,GAAI,GAAG,MAAM,KAAG,MAG5C,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,UAAU,GAAI,GAAG,MAAM,EAAE,GAAG,MAAM,EAAE,GAAG,MAAM,KAAG,GA2B5D,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,UAAU,GAAI,GAAG,GAAG,EAAE,GAAG,UAAU,EAAE,GAAG,SAAS,KAAG,GAYhE,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAI,GAAG,MAAM,EAAE,GAAG,MAAM,EAAE,GAAG,MAAM,KAAG,MAMtE,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,GAAG,GAAG,EAAE,GAAG,UAAU,EAAE,GAAG,SAAS,KAAG,MAGhE,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,GAAG,GAAG,EAAE,GAAG,UAAU,EAAE,GAAG,SAAS,KAAG,MAGvE,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,GAAG,GAAG,EAAE,GAAG,UAAU,EAAE,GAAG,SAAS,KAAG,MACU,CAAC;AAE/E,eAAO,MAAM,iBAAiB,GAAI,KAAK,MAAM,KAAG,GAG/C,CAAC;AAIF,eAAO,MAAM,gBAAgB,GAAI,KAAK,MAAM,KAAG,GAI9C,CAAC"}
package/dist/colors.js ADDED
@@ -0,0 +1,106 @@
1
+ import { round } from './maths.js';
2
+ /**
3
+ * Converts an RGB color to a hex color.
4
+ */
5
+ export const rgb_to_hex = (r, g, b) => (r << 16) + (g << 8) + b;
6
+ /**
7
+ * Converts a hex color to an RGB color.
8
+ */
9
+ export const hex_to_rgb = (hex) => [(hex >> 16) & 255, (hex >> 8) & 255, hex & 255];
10
+ export const hex_string_to_rgb = (hex) => {
11
+ var h = hex[0] === '#' ? hex.substring(1) : hex;
12
+ if (h.length !== 6 && h.length !== 8)
13
+ throw new Error('invalid hex string');
14
+ return [parseInt(h[0] + h[1], 16), parseInt(h[2] + h[3], 16), parseInt(h[4] + h[5], 16)];
15
+ };
16
+ export const rgb_to_hex_string = (r, g, b) => '#' + to_hex_component(r) + to_hex_component(g) + to_hex_component(b);
17
+ export const to_hex_component = (v) => {
18
+ var h = v.toString(16);
19
+ return h.length === 1 ? '0' + h : h;
20
+ };
21
+ /**
22
+ * Converts an RGB color value to HSL. Conversion formula
23
+ * adapted from http://wikipedia.org/wiki/HSL_color_space.
24
+ * Values r/g/b are in the range [0,255] and
25
+ * returns h/s/l in the range [0,1].
26
+ */
27
+ export const rgb_to_hsl = (r, g, b) => {
28
+ var r2 = r / 255;
29
+ var g2 = g / 255;
30
+ var b2 = b / 255;
31
+ var max = Math.max(r2, g2, b2);
32
+ var min = Math.min(r2, g2, b2);
33
+ var l = (max + min) / 2;
34
+ var h, s;
35
+ if (max === min) {
36
+ h = s = 0; // achromatic
37
+ }
38
+ else {
39
+ var d = max - min;
40
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
41
+ switch (max) {
42
+ case r2:
43
+ h = (g2 - b2) / d + (g2 < b2 ? 6 : 0);
44
+ break;
45
+ case g2:
46
+ h = (b2 - r2) / d + 2;
47
+ break;
48
+ case b2:
49
+ h = (r2 - g2) / d + 4;
50
+ break;
51
+ }
52
+ h /= 6;
53
+ }
54
+ return [h, round(s, 2), round(l, 2)];
55
+ };
56
+ /**
57
+ * Converts an HSL color value to RGB. Conversion formula
58
+ * adapted from http://wikipedia.org/wiki/HSL_color_space.
59
+ * Values h/s/l are in the range [0,1] and
60
+ * returns r/g/b in the range [0,255].
61
+ */
62
+ export const hsl_to_rgb = (h, s, l) => {
63
+ var r, g, b;
64
+ if (s === 0) {
65
+ r = g = b = l; // achromatic
66
+ }
67
+ else {
68
+ var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
69
+ var p = 2 * l - q;
70
+ r = hue_to_rgb_component(p, q, h + 1 / 3);
71
+ g = hue_to_rgb_component(p, q, h);
72
+ b = hue_to_rgb_component(p, q, h - 1 / 3);
73
+ }
74
+ return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
75
+ };
76
+ export const hue_to_rgb_component = (p, q, t) => {
77
+ var t2 = t < 0 ? t + 1 : t > 1 ? t - 1 : t;
78
+ if (t2 < 1 / 6)
79
+ return p + (q - p) * 6 * t2;
80
+ if (t2 < 1 / 2)
81
+ return q;
82
+ if (t2 < 2 / 3)
83
+ return p + (q - p) * (2 / 3 - t2) * 6;
84
+ return p;
85
+ };
86
+ export const hsl_to_hex = (h, s, l) => {
87
+ var rgb = hsl_to_rgb(h, s, l); // TODO could safely use the optimized variant
88
+ return rgb_to_hex(rgb[0], rgb[1], rgb[2]);
89
+ };
90
+ export const hsl_to_hex_string = (h, s, l) => {
91
+ var rgb = hsl_to_rgb(h, s, l); // TODO could safely use the optimized variant
92
+ return rgb_to_hex_string(rgb[0], rgb[1], rgb[2]);
93
+ };
94
+ export const hsl_to_string = (h, s, l) => `hsl(${Math.round(h * 360)} ${Math.round(s * 100)}% ${Math.round(l * 100)}%)`;
95
+ export const hex_string_to_hsl = (hex) => {
96
+ var rgb = hex_string_to_rgb(hex); // TODO could safely use the optimized variant
97
+ return rgb_to_hsl(rgb[0], rgb[1], rgb[2]);
98
+ };
99
+ const HSL_STRING_MATCHER = /^(hsl\()?\s*(\d+),?\s*(\d+)%,?\s*(\d+)%/;
100
+ export const parse_hsl_string = (hsl) => {
101
+ var match = HSL_STRING_MATCHER.exec(hsl);
102
+ if (!match)
103
+ throw new Error('invalid HSL string');
104
+ return [Number(match[2]) / 360, Number(match[3]) / 100, Number(match[4]) / 100];
105
+ };
106
+ // TODO either add an hsla variant or support alpha in the hsl variant
@@ -0,0 +1,7 @@
1
+ export type Counter = () => number;
2
+ export type CreateCounter = (initial?: number) => Counter;
3
+ /**
4
+ * Creates a counter constructor function, starting at `0`.
5
+ */
6
+ export declare const create_counter: CreateCounter;
7
+ //# sourceMappingURL=counter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"counter.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/counter.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC;AAEnC,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;AAE1D;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,aAG5B,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Creates a counter constructor function, starting at `0`.
3
+ */
4
+ export const create_counter = (count = 0) => {
5
+ let c = count;
6
+ return () => c++;
7
+ };
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Deep equality comparison that checks both structure and type.
3
+ *
4
+ * Key behaviors:
5
+ *
6
+ * - Compares by constructor to prevent type confusion (security: `{}` ≠ `[]`, `{}` ≠ `new Map()`, `new ClassA()` ≠ `new ClassB()`)
7
+ * - Prevents asymmetry bugs: `deep_equal(a, b)` always equals `deep_equal(b, a)`
8
+ * - Compares only enumerable own properties (ignores prototypes, symbols, non-enumerable)
9
+ * - Special handling for: Date (timestamp), Number/Boolean (boxed primitives), Error (message/name)
10
+ * - Promises always return false (cannot be meaningfully compared)
11
+ * - Maps/Sets compare by reference for object keys/values
12
+ *
13
+ * @param a first value to compare
14
+ * @param b second value to compare
15
+ * @returns true if deeply equal, false otherwise
16
+ */
17
+ export declare const deep_equal: (a: unknown, b: unknown) => boolean;
18
+ //# sourceMappingURL=deep_equal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deep_equal.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/deep_equal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,UAAU,GAAI,GAAG,OAAO,EAAE,GAAG,OAAO,KAAG,OA0InD,CAAC"}