@tldraw/utils 4.1.0-next.b6dfe9bccde9 → 4.1.0-next.b73a0d46b63f
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-cjs/index.d.ts +1350 -80
- package/dist-cjs/index.js +5 -5
- package/dist-cjs/lib/ExecutionQueue.js +79 -0
- package/dist-cjs/lib/ExecutionQueue.js.map +2 -2
- package/dist-cjs/lib/PerformanceTracker.js +43 -0
- package/dist-cjs/lib/PerformanceTracker.js.map +2 -2
- package/dist-cjs/lib/array.js +3 -1
- package/dist-cjs/lib/array.js.map +2 -2
- package/dist-cjs/lib/bind.js.map +2 -2
- package/dist-cjs/lib/cache.js +27 -5
- package/dist-cjs/lib/cache.js.map +2 -2
- package/dist-cjs/lib/control.js +12 -0
- package/dist-cjs/lib/control.js.map +2 -2
- package/dist-cjs/lib/debounce.js.map +2 -2
- package/dist-cjs/lib/error.js.map +2 -2
- package/dist-cjs/lib/file.js +76 -11
- package/dist-cjs/lib/file.js.map +2 -2
- package/dist-cjs/lib/function.js.map +2 -2
- package/dist-cjs/lib/hash.js.map +2 -2
- package/dist-cjs/lib/id.js.map +2 -2
- package/dist-cjs/lib/iterable.js.map +2 -2
- package/dist-cjs/lib/json-value.js.map +1 -1
- package/dist-cjs/lib/media/apng.js.map +2 -2
- package/dist-cjs/lib/media/avif.js.map +2 -2
- package/dist-cjs/lib/media/gif.js.map +2 -2
- package/dist-cjs/lib/media/media.js +130 -4
- package/dist-cjs/lib/media/media.js.map +2 -2
- package/dist-cjs/lib/media/png.js +141 -0
- package/dist-cjs/lib/media/png.js.map +2 -2
- package/dist-cjs/lib/media/webp.js +1 -0
- package/dist-cjs/lib/media/webp.js.map +2 -2
- package/dist-cjs/lib/network.js.map +2 -2
- package/dist-cjs/lib/number.js.map +2 -2
- package/dist-cjs/lib/object.js +1 -1
- package/dist-cjs/lib/object.js.map +2 -2
- package/dist-cjs/lib/perf.js.map +2 -2
- package/dist-cjs/lib/reordering.js.map +2 -2
- package/dist-cjs/lib/retry.js.map +2 -2
- package/dist-cjs/lib/sort.js.map +2 -2
- package/dist-cjs/lib/storage.js.map +2 -2
- package/dist-cjs/lib/stringEnum.js.map +2 -2
- package/dist-cjs/lib/throttle.js.map +2 -2
- package/dist-cjs/lib/timers.js +103 -4
- package/dist-cjs/lib/timers.js.map +2 -2
- package/dist-cjs/lib/types.js.map +1 -1
- package/dist-cjs/lib/url.js.map +2 -2
- package/dist-cjs/lib/value.js.map +2 -2
- package/dist-cjs/lib/version.js.map +2 -2
- package/dist-cjs/lib/warn.js.map +2 -2
- package/dist-esm/index.d.mts +1350 -80
- package/dist-esm/index.mjs +1 -1
- package/dist-esm/lib/ExecutionQueue.mjs +79 -0
- package/dist-esm/lib/ExecutionQueue.mjs.map +2 -2
- package/dist-esm/lib/PerformanceTracker.mjs +43 -0
- package/dist-esm/lib/PerformanceTracker.mjs.map +2 -2
- package/dist-esm/lib/array.mjs +3 -1
- package/dist-esm/lib/array.mjs.map +2 -2
- package/dist-esm/lib/bind.mjs.map +2 -2
- package/dist-esm/lib/cache.mjs +27 -5
- package/dist-esm/lib/cache.mjs.map +2 -2
- package/dist-esm/lib/control.mjs +12 -0
- package/dist-esm/lib/control.mjs.map +2 -2
- package/dist-esm/lib/debounce.mjs.map +2 -2
- package/dist-esm/lib/error.mjs.map +2 -2
- package/dist-esm/lib/file.mjs +76 -11
- package/dist-esm/lib/file.mjs.map +2 -2
- package/dist-esm/lib/function.mjs.map +2 -2
- package/dist-esm/lib/hash.mjs.map +2 -2
- package/dist-esm/lib/id.mjs.map +2 -2
- package/dist-esm/lib/iterable.mjs.map +2 -2
- package/dist-esm/lib/media/apng.mjs.map +2 -2
- package/dist-esm/lib/media/avif.mjs.map +2 -2
- package/dist-esm/lib/media/gif.mjs.map +2 -2
- package/dist-esm/lib/media/media.mjs +130 -4
- package/dist-esm/lib/media/media.mjs.map +2 -2
- package/dist-esm/lib/media/png.mjs +141 -0
- package/dist-esm/lib/media/png.mjs.map +2 -2
- package/dist-esm/lib/media/webp.mjs +1 -0
- package/dist-esm/lib/media/webp.mjs.map +2 -2
- package/dist-esm/lib/network.mjs.map +2 -2
- package/dist-esm/lib/number.mjs.map +2 -2
- package/dist-esm/lib/object.mjs.map +2 -2
- package/dist-esm/lib/perf.mjs.map +2 -2
- package/dist-esm/lib/reordering.mjs.map +2 -2
- package/dist-esm/lib/retry.mjs.map +2 -2
- package/dist-esm/lib/sort.mjs.map +2 -2
- package/dist-esm/lib/storage.mjs.map +2 -2
- package/dist-esm/lib/stringEnum.mjs.map +2 -2
- package/dist-esm/lib/throttle.mjs.map +2 -2
- package/dist-esm/lib/timers.mjs +103 -4
- package/dist-esm/lib/timers.mjs.map +2 -2
- package/dist-esm/lib/url.mjs.map +2 -2
- package/dist-esm/lib/value.mjs.map +2 -2
- package/dist-esm/lib/version.mjs.map +2 -2
- package/dist-esm/lib/warn.mjs.map +2 -2
- package/package.json +1 -1
- package/src/lib/ExecutionQueue.test.ts +162 -20
- package/src/lib/ExecutionQueue.ts +110 -1
- package/src/lib/PerformanceTracker.test.ts +124 -0
- package/src/lib/PerformanceTracker.ts +63 -1
- package/src/lib/array.test.ts +263 -1
- package/src/lib/array.ts +183 -14
- package/src/lib/bind.test.ts +47 -0
- package/src/lib/bind.ts +69 -4
- package/src/lib/cache.test.ts +73 -0
- package/src/lib/cache.ts +47 -6
- package/src/lib/control.test.ts +50 -0
- package/src/lib/control.ts +198 -9
- package/src/lib/debounce.ts +28 -3
- package/src/lib/error.test.ts +60 -0
- package/src/lib/error.ts +27 -1
- package/src/lib/file.test.ts +49 -0
- package/src/lib/file.ts +117 -12
- package/src/lib/function.ts +11 -0
- package/src/lib/hash.test.ts +99 -0
- package/src/lib/hash.ts +69 -2
- package/src/lib/id.test.ts +32 -0
- package/src/lib/id.ts +53 -5
- package/src/lib/iterable.test.ts +25 -0
- package/src/lib/iterable.ts +4 -5
- package/src/lib/json-value.ts +71 -4
- package/src/lib/media/apng.test.ts +67 -0
- package/src/lib/media/apng.ts +38 -21
- package/src/lib/media/avif.test.ts +26 -0
- package/src/lib/media/avif.ts +34 -0
- package/src/lib/media/gif.test.ts +52 -0
- package/src/lib/media/gif.ts +25 -2
- package/src/lib/media/media.test.ts +58 -0
- package/src/lib/media/media.ts +220 -11
- package/src/lib/media/png.ts +162 -1
- package/src/lib/media/webp.test.ts +81 -0
- package/src/lib/media/webp.ts +33 -1
- package/src/lib/network.test.ts +38 -0
- package/src/lib/network.ts +6 -0
- package/src/lib/number.test.ts +74 -0
- package/src/lib/number.ts +29 -5
- package/src/lib/object.test.ts +236 -0
- package/src/lib/object.ts +194 -14
- package/src/lib/perf.ts +75 -3
- package/src/lib/reordering.test.ts +168 -0
- package/src/lib/reordering.ts +62 -4
- package/src/lib/retry.test.ts +77 -0
- package/src/lib/retry.ts +47 -1
- package/src/lib/sort.test.ts +36 -0
- package/src/lib/sort.ts +22 -1
- package/src/lib/storage.test.ts +130 -0
- package/src/lib/storage.tsx +54 -8
- package/src/lib/stringEnum.ts +20 -1
- package/src/lib/throttle.ts +46 -8
- package/src/lib/timers.test.ts +75 -0
- package/src/lib/timers.ts +124 -5
- package/src/lib/types.ts +126 -4
- package/src/lib/url.test.ts +44 -0
- package/src/lib/url.ts +40 -1
- package/src/lib/value.test.ts +102 -0
- package/src/lib/value.ts +67 -3
- package/src/lib/version.test.ts +494 -56
- package/src/lib/version.ts +36 -1
- package/src/lib/warn.test.ts +64 -0
- package/src/lib/warn.ts +43 -2
package/dist-cjs/index.js
CHANGED
|
@@ -131,10 +131,10 @@ __export(index_exports, {
|
|
|
131
131
|
});
|
|
132
132
|
module.exports = __toCommonJS(index_exports);
|
|
133
133
|
var import_version = require("./lib/version");
|
|
134
|
-
var import_lodash = __toESM(require("lodash.isequal"));
|
|
135
|
-
var import_lodash2 = __toESM(require("lodash.isequalwith"));
|
|
136
|
-
var import_lodash3 = __toESM(require("lodash.throttle"));
|
|
137
|
-
var import_lodash4 = __toESM(require("lodash.uniq"));
|
|
134
|
+
var import_lodash = __toESM(require("lodash.isequal"), 1);
|
|
135
|
+
var import_lodash2 = __toESM(require("lodash.isequalwith"), 1);
|
|
136
|
+
var import_lodash3 = __toESM(require("lodash.throttle"), 1);
|
|
137
|
+
var import_lodash4 = __toESM(require("lodash.uniq"), 1);
|
|
138
138
|
var import_array = require("./lib/array");
|
|
139
139
|
var import_bind = require("./lib/bind");
|
|
140
140
|
var import_cache = require("./lib/cache");
|
|
@@ -167,7 +167,7 @@ var import_version2 = require("./lib/version");
|
|
|
167
167
|
var import_warn = require("./lib/warn");
|
|
168
168
|
(0, import_version.registerTldrawLibraryVersion)(
|
|
169
169
|
"@tldraw/utils",
|
|
170
|
-
"4.1.0-next.
|
|
170
|
+
"4.1.0-next.b73a0d46b63f",
|
|
171
171
|
"cjs"
|
|
172
172
|
);
|
|
173
173
|
//# sourceMappingURL=index.js.map
|
|
@@ -23,11 +23,45 @@ __export(ExecutionQueue_exports, {
|
|
|
23
23
|
module.exports = __toCommonJS(ExecutionQueue_exports);
|
|
24
24
|
var import_control = require("./control");
|
|
25
25
|
class ExecutionQueue {
|
|
26
|
+
/**
|
|
27
|
+
* Creates a new ExecutionQueue.
|
|
28
|
+
*
|
|
29
|
+
* Creates a new execution queue that will process tasks sequentially.
|
|
30
|
+
* If a timeout is provided, there will be a delay between each task execution,
|
|
31
|
+
* which is useful for rate limiting or controlling execution flow.
|
|
32
|
+
*
|
|
33
|
+
* timeout - Optional delay in milliseconds between task executions
|
|
34
|
+
* @example
|
|
35
|
+
* ```ts
|
|
36
|
+
* // Create queue without delay
|
|
37
|
+
* const fastQueue = new ExecutionQueue()
|
|
38
|
+
*
|
|
39
|
+
* // Create queue with 500ms delay between tasks
|
|
40
|
+
* const slowQueue = new ExecutionQueue(500)
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
26
43
|
constructor(timeout) {
|
|
27
44
|
this.timeout = timeout;
|
|
28
45
|
}
|
|
29
46
|
queue = [];
|
|
30
47
|
running = false;
|
|
48
|
+
/**
|
|
49
|
+
* Checks if the queue is empty and not currently running a task.
|
|
50
|
+
*
|
|
51
|
+
* Determines whether the execution queue has completed all tasks and is idle.
|
|
52
|
+
* Returns true only when there are no pending tasks in the queue AND no task is currently being executed.
|
|
53
|
+
*
|
|
54
|
+
* @returns True if the queue has no pending tasks and is not currently executing
|
|
55
|
+
* @example
|
|
56
|
+
* ```ts
|
|
57
|
+
* const queue = new ExecutionQueue()
|
|
58
|
+
*
|
|
59
|
+
* console.log(queue.isEmpty()) // true - queue is empty
|
|
60
|
+
*
|
|
61
|
+
* queue.push(() => console.log('task'))
|
|
62
|
+
* console.log(queue.isEmpty()) // false - task is running/pending
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
31
65
|
isEmpty() {
|
|
32
66
|
return this.queue.length === 0 && !this.running;
|
|
33
67
|
}
|
|
@@ -46,12 +80,57 @@ class ExecutionQueue {
|
|
|
46
80
|
this.running = false;
|
|
47
81
|
}
|
|
48
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* Adds a task to the queue and returns a promise that resolves with the task's result.
|
|
85
|
+
*
|
|
86
|
+
* Enqueues a task for sequential execution. The task will be executed after all
|
|
87
|
+
* previously queued tasks have completed. If a timeout was specified in the constructor,
|
|
88
|
+
* there will be a delay between this task and the next one.
|
|
89
|
+
*
|
|
90
|
+
* @param task - The function to execute (can be sync or async)
|
|
91
|
+
* @returns Promise that resolves with the task's return value
|
|
92
|
+
* @example
|
|
93
|
+
* ```ts
|
|
94
|
+
* const queue = new ExecutionQueue(100)
|
|
95
|
+
*
|
|
96
|
+
* // Add async task
|
|
97
|
+
* const result = await queue.push(async () => {
|
|
98
|
+
* const response = await fetch('/api/data')
|
|
99
|
+
* return response.json()
|
|
100
|
+
* })
|
|
101
|
+
*
|
|
102
|
+
* // Add sync task
|
|
103
|
+
* const number = await queue.push(() => 42)
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
49
106
|
async push(task) {
|
|
50
107
|
return new Promise((resolve, reject) => {
|
|
51
108
|
this.queue.push(() => Promise.resolve(task()).then(resolve).catch(reject));
|
|
52
109
|
this.run();
|
|
53
110
|
});
|
|
54
111
|
}
|
|
112
|
+
/**
|
|
113
|
+
* Clears all pending tasks from the queue.
|
|
114
|
+
*
|
|
115
|
+
* Immediately removes all pending tasks from the queue. Any currently
|
|
116
|
+
* running task will complete normally, but no additional tasks will be executed.
|
|
117
|
+
* This method does not wait for the current task to finish.
|
|
118
|
+
*
|
|
119
|
+
* @returns void
|
|
120
|
+
* @example
|
|
121
|
+
* ```ts
|
|
122
|
+
* const queue = new ExecutionQueue()
|
|
123
|
+
*
|
|
124
|
+
* // Add several tasks
|
|
125
|
+
* queue.push(() => console.log('task 1'))
|
|
126
|
+
* queue.push(() => console.log('task 2'))
|
|
127
|
+
* queue.push(() => console.log('task 3'))
|
|
128
|
+
*
|
|
129
|
+
* // Clear all pending tasks
|
|
130
|
+
* queue.close()
|
|
131
|
+
* // Only 'task 1' will execute if it was already running
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
55
134
|
close() {
|
|
56
135
|
this.queue = [];
|
|
57
136
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/ExecutionQueue.ts"],
|
|
4
|
-
"sourcesContent": ["import { sleep } from './control'\n\n
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAAsB;
|
|
4
|
+
"sourcesContent": ["import { sleep } from './control'\n\n/**\n * A queue that executes tasks sequentially with optional delay between tasks.\n *\n * ExecutionQueue ensures that tasks are executed one at a time in the order they were added,\n * with an optional timeout delay between each task execution. This is useful for rate limiting,\n * preventing race conditions, or controlling the flow of asynchronous operations.\n *\n * @example\n * ```ts\n * // Create a queue with 100ms delay between tasks\n * const queue = new ExecutionQueue(100)\n *\n * // Add tasks to the queue\n * const result1 = await queue.push(() => fetch('/api/data'))\n * const result2 = await queue.push(async () => {\n * const data = await processData()\n * return data\n * })\n *\n * // Check if queue is empty\n * if (queue.isEmpty()) {\n * console.log('All tasks completed')\n * }\n *\n * // Clean up\n * queue.close()\n * ```\n *\n * @internal\n */\nexport class ExecutionQueue {\n\tprivate queue: (() => Promise<any>)[] = []\n\tprivate running = false\n\n\t/**\n\t * Creates a new ExecutionQueue.\n\t *\n\t * Creates a new execution queue that will process tasks sequentially.\n\t * If a timeout is provided, there will be a delay between each task execution,\n\t * which is useful for rate limiting or controlling execution flow.\n\t *\n\t * timeout - Optional delay in milliseconds between task executions\n\t * @example\n\t * ```ts\n\t * // Create queue without delay\n\t * const fastQueue = new ExecutionQueue()\n\t *\n\t * // Create queue with 500ms delay between tasks\n\t * const slowQueue = new ExecutionQueue(500)\n\t * ```\n\t */\n\tconstructor(private readonly timeout?: number) {}\n\n\t/**\n\t * Checks if the queue is empty and not currently running a task.\n\t *\n\t * Determines whether the execution queue has completed all tasks and is idle.\n\t * Returns true only when there are no pending tasks in the queue AND no task is currently being executed.\n\t *\n\t * @returns True if the queue has no pending tasks and is not currently executing\n\t * @example\n\t * ```ts\n\t * const queue = new ExecutionQueue()\n\t *\n\t * console.log(queue.isEmpty()) // true - queue is empty\n\t *\n\t * queue.push(() => console.log('task'))\n\t * console.log(queue.isEmpty()) // false - task is running/pending\n\t * ```\n\t */\n\tisEmpty() {\n\t\treturn this.queue.length === 0 && !this.running\n\t}\n\n\tprivate async run() {\n\t\tif (this.running) return\n\t\ttry {\n\t\t\tthis.running = true\n\t\t\twhile (this.queue.length) {\n\t\t\t\tconst task = this.queue.shift()!\n\t\t\t\tawait task()\n\t\t\t\tif (this.timeout) {\n\t\t\t\t\tawait sleep(this.timeout)\n\t\t\t\t}\n\t\t\t}\n\t\t} finally {\n\t\t\t// this try/finally should not be needed because the tasks don't throw\n\t\t\t// but better safe than sorry\n\t\t\t// console.log('\\n\\n\\nrunning false\\n\\n\\n')\n\t\t\tthis.running = false\n\t\t}\n\t}\n\n\t/**\n\t * Adds a task to the queue and returns a promise that resolves with the task's result.\n\t *\n\t * Enqueues a task for sequential execution. The task will be executed after all\n\t * previously queued tasks have completed. If a timeout was specified in the constructor,\n\t * there will be a delay between this task and the next one.\n\t *\n\t * @param task - The function to execute (can be sync or async)\n\t * @returns Promise that resolves with the task's return value\n\t * @example\n\t * ```ts\n\t * const queue = new ExecutionQueue(100)\n\t *\n\t * // Add async task\n\t * const result = await queue.push(async () => {\n\t * const response = await fetch('/api/data')\n\t * return response.json()\n\t * })\n\t *\n\t * // Add sync task\n\t * const number = await queue.push(() => 42)\n\t * ```\n\t */\n\tasync push<T>(task: () => T): Promise<Awaited<T>> {\n\t\treturn new Promise<Awaited<T>>((resolve, reject) => {\n\t\t\tthis.queue.push(() => Promise.resolve(task()).then(resolve).catch(reject))\n\t\t\tthis.run()\n\t\t})\n\t}\n\n\t/**\n\t * Clears all pending tasks from the queue.\n\t *\n\t * Immediately removes all pending tasks from the queue. Any currently\n\t * running task will complete normally, but no additional tasks will be executed.\n\t * This method does not wait for the current task to finish.\n\t *\n\t * @returns void\n\t * @example\n\t * ```ts\n\t * const queue = new ExecutionQueue()\n\t *\n\t * // Add several tasks\n\t * queue.push(() => console.log('task 1'))\n\t * queue.push(() => console.log('task 2'))\n\t * queue.push(() => console.log('task 3'))\n\t *\n\t * // Clear all pending tasks\n\t * queue.close()\n\t * // Only 'task 1' will execute if it was already running\n\t * ```\n\t */\n\tclose() {\n\t\tthis.queue = []\n\t}\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAAsB;AAgCf,MAAM,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAqB3B,YAA6B,SAAkB;AAAlB;AAAA,EAAmB;AAAA,EApBxC,QAAgC,CAAC;AAAA,EACjC,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsClB,UAAU;AACT,WAAO,KAAK,MAAM,WAAW,KAAK,CAAC,KAAK;AAAA,EACzC;AAAA,EAEA,MAAc,MAAM;AACnB,QAAI,KAAK,QAAS;AAClB,QAAI;AACH,WAAK,UAAU;AACf,aAAO,KAAK,MAAM,QAAQ;AACzB,cAAM,OAAO,KAAK,MAAM,MAAM;AAC9B,cAAM,KAAK;AACX,YAAI,KAAK,SAAS;AACjB,oBAAM,sBAAM,KAAK,OAAO;AAAA,QACzB;AAAA,MACD;AAAA,IACD,UAAE;AAID,WAAK,UAAU;AAAA,IAChB;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAyBA,MAAM,KAAQ,MAAoC;AACjD,WAAO,IAAI,QAAoB,CAAC,SAAS,WAAW;AACnD,WAAK,MAAM,KAAK,MAAM,QAAQ,QAAQ,KAAK,CAAC,EAAE,KAAK,OAAO,EAAE,MAAM,MAAM,CAAC;AACzE,WAAK,IAAI;AAAA,IACV,CAAC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAwBA,QAAQ;AACP,SAAK,QAAQ,CAAC;AAAA,EACf;AACD;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -28,12 +28,28 @@ class PerformanceTracker {
|
|
|
28
28
|
frames = 0;
|
|
29
29
|
started = false;
|
|
30
30
|
frame = null;
|
|
31
|
+
/**
|
|
32
|
+
* Records animation frames to calculate frame rate.
|
|
33
|
+
* Called automatically during performance tracking.
|
|
34
|
+
*/
|
|
31
35
|
// eslint-disable-next-line local/prefer-class-methods
|
|
32
36
|
recordFrame = () => {
|
|
33
37
|
this.frames++;
|
|
34
38
|
if (!this.started) return;
|
|
35
39
|
this.frame = requestAnimationFrame(this.recordFrame);
|
|
36
40
|
};
|
|
41
|
+
/**
|
|
42
|
+
* Starts performance tracking for a named operation.
|
|
43
|
+
*
|
|
44
|
+
* @param name - A descriptive name for the operation being tracked
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* tracker.start('canvas-render')
|
|
49
|
+
* // ... perform rendering operations
|
|
50
|
+
* tracker.stop()
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
37
53
|
start(name) {
|
|
38
54
|
this.name = name;
|
|
39
55
|
this.frames = 0;
|
|
@@ -42,6 +58,21 @@ class PerformanceTracker {
|
|
|
42
58
|
this.frame = requestAnimationFrame(this.recordFrame);
|
|
43
59
|
this.startTime = performance.now();
|
|
44
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* Stops performance tracking and logs results to the console.
|
|
63
|
+
*
|
|
64
|
+
* Displays the operation name, frame rate, and uses color coding:
|
|
65
|
+
* - Green background: \> 55 FPS (good performance)
|
|
66
|
+
* - Yellow background: 30-55 FPS (moderate performance)
|
|
67
|
+
* - Red background: \< 30 FPS (poor performance)
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```ts
|
|
71
|
+
* tracker.start('interaction')
|
|
72
|
+
* handleUserInteraction()
|
|
73
|
+
* tracker.stop() // Logs: "Perf Interaction 60 fps"
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
45
76
|
stop() {
|
|
46
77
|
this.started = false;
|
|
47
78
|
if (this.frame !== null) cancelAnimationFrame(this.frame);
|
|
@@ -58,6 +89,18 @@ class PerformanceTracker {
|
|
|
58
89
|
"font-weight: normal"
|
|
59
90
|
);
|
|
60
91
|
}
|
|
92
|
+
/**
|
|
93
|
+
* Checks whether performance tracking is currently active.
|
|
94
|
+
*
|
|
95
|
+
* @returns True if tracking is in progress, false otherwise
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```ts
|
|
99
|
+
* if (!tracker.isStarted()) {
|
|
100
|
+
* tracker.start('new-operation')
|
|
101
|
+
* }
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
61
104
|
isStarted() {
|
|
62
105
|
return this.started;
|
|
63
106
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/PerformanceTracker.ts"],
|
|
4
|
-
"sourcesContent": ["import { PERFORMANCE_COLORS, PERFORMANCE_PREFIX_COLOR } from './perf'\n\n
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAA6D;
|
|
4
|
+
"sourcesContent": ["import { PERFORMANCE_COLORS, PERFORMANCE_PREFIX_COLOR } from './perf'\n\n/**\n * A utility class for measuring and tracking frame rate performance during operations.\n * Provides visual feedback in the browser console with color-coded FPS indicators.\n *\n * @example\n * ```ts\n * const tracker = new PerformanceTracker()\n *\n * tracker.start('render')\n * renderShapes()\n * tracker.stop() // Logs performance info to console\n *\n * // Check if tracking is active\n * if (tracker.isStarted()) {\n * console.log('Still tracking performance')\n * }\n * ```\n *\n * @public\n */\nexport class PerformanceTracker {\n\tprivate startTime = 0\n\tprivate name = ''\n\tprivate frames = 0\n\tprivate started = false\n\tprivate frame: number | null = null\n\n\t/**\n\t * Records animation frames to calculate frame rate.\n\t * Called automatically during performance tracking.\n\t */\n\t// eslint-disable-next-line local/prefer-class-methods\n\trecordFrame = () => {\n\t\tthis.frames++\n\t\tif (!this.started) return\n\t\t// eslint-disable-next-line no-restricted-globals\n\t\tthis.frame = requestAnimationFrame(this.recordFrame)\n\t}\n\n\t/**\n\t * Starts performance tracking for a named operation.\n\t *\n\t * @param name - A descriptive name for the operation being tracked\n\t *\n\t * @example\n\t * ```ts\n\t * tracker.start('canvas-render')\n\t * // ... perform rendering operations\n\t * tracker.stop()\n\t * ```\n\t */\n\tstart(name: string) {\n\t\tthis.name = name\n\t\tthis.frames = 0\n\t\tthis.started = true\n\t\tif (this.frame !== null) cancelAnimationFrame(this.frame)\n\t\t// eslint-disable-next-line no-restricted-globals\n\t\tthis.frame = requestAnimationFrame(this.recordFrame)\n\t\tthis.startTime = performance.now()\n\t}\n\n\t/**\n\t * Stops performance tracking and logs results to the console.\n\t *\n\t * Displays the operation name, frame rate, and uses color coding:\n\t * - Green background: \\> 55 FPS (good performance)\n\t * - Yellow background: 30-55 FPS (moderate performance)\n\t * - Red background: \\< 30 FPS (poor performance)\n\t *\n\t * @example\n\t * ```ts\n\t * tracker.start('interaction')\n\t * handleUserInteraction()\n\t * tracker.stop() // Logs: \"Perf Interaction 60 fps\"\n\t * ```\n\t */\n\tstop() {\n\t\tthis.started = false\n\t\tif (this.frame !== null) cancelAnimationFrame(this.frame)\n\t\tconst duration = (performance.now() - this.startTime) / 1000\n\t\tconst fps = duration === 0 ? 0 : Math.floor(this.frames / duration)\n\t\tconst background =\n\t\t\tfps > 55\n\t\t\t\t? PERFORMANCE_COLORS.Good\n\t\t\t\t: fps > 30\n\t\t\t\t\t? PERFORMANCE_COLORS.Mid\n\t\t\t\t\t: PERFORMANCE_COLORS.Poor\n\t\tconst color = background === PERFORMANCE_COLORS.Mid ? 'black' : 'white'\n\t\tconst capitalized = this.name[0].toUpperCase() + this.name.slice(1)\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.debug(\n\t\t\t`%cPerf%c ${capitalized} %c${fps}%c fps`,\n\t\t\t`color: white; background: ${PERFORMANCE_PREFIX_COLOR};padding: 2px;border-radius: 3px;`,\n\t\t\t'font-weight: normal',\n\t\t\t`font-weight: bold; padding: 2px; background: ${background};color: ${color};`,\n\t\t\t'font-weight: normal'\n\t\t)\n\t}\n\n\t/**\n\t * Checks whether performance tracking is currently active.\n\t *\n\t * @returns True if tracking is in progress, false otherwise\n\t *\n\t * @example\n\t * ```ts\n\t * if (!tracker.isStarted()) {\n\t * tracker.start('new-operation')\n\t * }\n\t * ```\n\t */\n\tisStarted() {\n\t\treturn this.started\n\t}\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAA6D;AAsBtD,MAAM,mBAAmB;AAAA,EACvB,YAAY;AAAA,EACZ,OAAO;AAAA,EACP,SAAS;AAAA,EACT,UAAU;AAAA,EACV,QAAuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO/B,cAAc,MAAM;AACnB,SAAK;AACL,QAAI,CAAC,KAAK,QAAS;AAEnB,SAAK,QAAQ,sBAAsB,KAAK,WAAW;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,MAAM,MAAc;AACnB,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,UAAU;AACf,QAAI,KAAK,UAAU,KAAM,sBAAqB,KAAK,KAAK;AAExD,SAAK,QAAQ,sBAAsB,KAAK,WAAW;AACnD,SAAK,YAAY,YAAY,IAAI;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBA,OAAO;AACN,SAAK,UAAU;AACf,QAAI,KAAK,UAAU,KAAM,sBAAqB,KAAK,KAAK;AACxD,UAAM,YAAY,YAAY,IAAI,IAAI,KAAK,aAAa;AACxD,UAAM,MAAM,aAAa,IAAI,IAAI,KAAK,MAAM,KAAK,SAAS,QAAQ;AAClE,UAAM,aACL,MAAM,KACH,+BAAmB,OACnB,MAAM,KACL,+BAAmB,MACnB,+BAAmB;AACxB,UAAM,QAAQ,eAAe,+BAAmB,MAAM,UAAU;AAChE,UAAM,cAAc,KAAK,KAAK,CAAC,EAAE,YAAY,IAAI,KAAK,KAAK,MAAM,CAAC;AAElE,YAAQ;AAAA,MACP,YAAY,WAAW,MAAM,GAAG;AAAA,MAChC,6BAA6B,oCAAwB;AAAA,MACrD;AAAA,MACA,gDAAgD,UAAU,WAAW,KAAK;AAAA,MAC1E;AAAA,IACD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,YAAY;AACX,WAAO,KAAK;AAAA,EACb;AACD;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist-cjs/lib/array.js
CHANGED
|
@@ -30,7 +30,9 @@ __export(array_exports, {
|
|
|
30
30
|
});
|
|
31
31
|
module.exports = __toCommonJS(array_exports);
|
|
32
32
|
function rotateArray(arr, offset) {
|
|
33
|
-
|
|
33
|
+
if (arr.length === 0) return [];
|
|
34
|
+
const normalizedOffset = (Math.abs(offset) % arr.length + arr.length) % arr.length;
|
|
35
|
+
return [...arr.slice(normalizedOffset), ...arr.slice(0, normalizedOffset)];
|
|
34
36
|
}
|
|
35
37
|
function dedupe(input, equals) {
|
|
36
38
|
const result = [];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/array.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Rotate the contents of an array.\n *\n * @public\n */\nexport function rotateArray<T>(arr: T[], offset: number): T[] {\n\
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;
|
|
4
|
+
"sourcesContent": ["/**\n * Rotate the contents of an array by a specified offset.\n *\n * Creates a new array with elements shifted to the left by the specified number of positions.\n * Both positive and negative offsets result in left shifts (elements move left, with elements\n * from the front wrapping to the back).\n *\n * @param arr - The array to rotate\n * @param offset - The number of positions to shift left (both positive and negative values shift left)\n * @returns A new array with elements shifted left by the specified offset\n *\n * @example\n * ```ts\n * rotateArray([1, 2, 3, 4], 1) // [2, 3, 4, 1]\n * rotateArray([1, 2, 3, 4], -1) // [2, 3, 4, 1]\n * rotateArray(['a', 'b', 'c'], 2) // ['c', 'a', 'b']\n * ```\n * @public\n */\nexport function rotateArray<T>(arr: T[], offset: number): T[] {\n\tif (arr.length === 0) return []\n\n\t// Based on the test expectations, both positive and negative offsets\n\t// should rotate left (shift elements to the left)\n\tconst normalizedOffset = ((Math.abs(offset) % arr.length) + arr.length) % arr.length\n\n\t// Slice the array at the offset point and concatenate\n\treturn [...arr.slice(normalizedOffset), ...arr.slice(0, normalizedOffset)]\n}\n\n/**\n * Remove duplicate items from an array.\n *\n * Creates a new array with duplicate items removed. Uses strict equality by default,\n * or a custom equality function if provided. Order of first occurrence is preserved.\n *\n * @param input - The array to deduplicate\n * @param equals - Optional custom equality function to compare items (defaults to strict equality)\n * @returns A new array with duplicate items removed\n *\n * @example\n * ```ts\n * dedupe([1, 2, 2, 3, 1]) // [1, 2, 3]\n * dedupe(['a', 'b', 'a', 'c']) // ['a', 'b', 'c']\n *\n * // With custom equality function\n * const objects = [{id: 1}, {id: 2}, {id: 1}]\n * dedupe(objects, (a, b) => a.id === b.id) // [{id: 1}, {id: 2}]\n * ```\n * @public\n */\nexport function dedupe<T>(input: T[], equals?: (a: any, b: any) => boolean): T[] {\n\tconst result: T[] = []\n\tmainLoop: for (const item of input) {\n\t\tfor (const existing of result) {\n\t\t\tif (equals ? equals(item, existing) : item === existing) {\n\t\t\t\tcontinue mainLoop\n\t\t\t}\n\t\t}\n\t\tresult.push(item)\n\t}\n\treturn result\n}\n\n/**\n * Remove null and undefined values from an array.\n *\n * Creates a new array with all null and undefined values filtered out.\n * The resulting array has a refined type that excludes null and undefined.\n *\n * @param arr - The array to compact\n * @returns A new array with null and undefined values removed\n *\n * @example\n * ```ts\n * compact([1, null, 2, undefined, 3]) // [1, 2, 3]\n * compact(['a', null, 'b', undefined]) // ['a', 'b']\n * ```\n * @internal\n */\nexport function compact<T>(arr: T[]): NonNullable<T>[] {\n\treturn arr.filter((i) => i !== undefined && i !== null) as any\n}\n\n/**\n * Get the last element of an array.\n *\n * Returns the last element of an array, or undefined if the array is empty.\n * Works with readonly arrays and preserves the element type.\n *\n * @param arr - The array to get the last element from\n * @returns The last element of the array, or undefined if the array is empty\n *\n * @example\n * ```ts\n * last([1, 2, 3]) // 3\n * last(['a', 'b', 'c']) // 'c'\n * last([]) // undefined\n * ```\n * @internal\n */\nexport function last<T>(arr: readonly T[]): T | undefined {\n\treturn arr[arr.length - 1]\n}\n\n/**\n * Find the item in an array with the minimum value according to a function.\n *\n * Finds the array item that produces the smallest value when passed through\n * the provided function. Returns undefined for empty arrays.\n *\n * @param arr - The array to search\n * @param fn - Function to compute the comparison value for each item\n * @returns The item with the minimum value, or undefined if the array is empty\n *\n * @example\n * ```ts\n * const people = [{name: 'Alice', age: 30}, {name: 'Bob', age: 25}]\n * minBy(people, p => p.age) // {name: 'Bob', age: 25}\n *\n * minBy([3, 1, 4, 1, 5], x => x) // 1\n * minBy([], x => x) // undefined\n * ```\n * @internal\n */\nexport function minBy<T>(arr: readonly T[], fn: (item: T) => number): T | undefined {\n\tlet min: T | undefined\n\tlet minVal = Infinity\n\tfor (const item of arr) {\n\t\tconst val = fn(item)\n\t\tif (val < minVal) {\n\t\t\tmin = item\n\t\t\tminVal = val\n\t\t}\n\t}\n\treturn min\n}\n\n/**\n * Find the item in an array with the maximum value according to a function.\n *\n * Finds the array item that produces the largest value when passed through\n * the provided function. Returns undefined for empty arrays.\n *\n * @param arr - The array to search\n * @param fn - Function to compute the comparison value for each item\n * @returns The item with the maximum value, or undefined if the array is empty\n *\n * @example\n * ```ts\n * const people = [{name: 'Alice', age: 30}, {name: 'Bob', age: 25}]\n * maxBy(people, p => p.age) // {name: 'Alice', age: 30}\n *\n * maxBy([3, 1, 4, 1, 5], x => x) // 5\n * maxBy([], x => x) // undefined\n * ```\n * @internal\n */\nexport function maxBy<T>(arr: readonly T[], fn: (item: T) => number): T | undefined {\n\tlet max: T | undefined\n\tlet maxVal: number = -Infinity\n\tfor (const item of arr) {\n\t\tconst val = fn(item)\n\t\tif (val > maxVal) {\n\t\t\tmax = item\n\t\t\tmaxVal = val\n\t\t}\n\t}\n\treturn max\n}\n\n/**\n * Split an array into two arrays based on a predicate function.\n *\n * Partitions an array into two arrays: one containing items that satisfy\n * the predicate, and another containing items that do not. The original array order is preserved.\n *\n * @param arr - The array to partition\n * @param predicate - The predicate function to test each item\n * @returns A tuple of two arrays: [satisfying items, non-satisfying items]\n *\n * @example\n * ```ts\n * const [evens, odds] = partition([1, 2, 3, 4, 5], x => x % 2 === 0)\n * // evens: [2, 4], odds: [1, 3, 5]\n *\n * const [adults, minors] = partition(\n * [{name: 'Alice', age: 30}, {name: 'Bob', age: 17}],\n * person => person.age >= 18\n * )\n * // adults: [{name: 'Alice', age: 30}], minors: [{name: 'Bob', age: 17}]\n * ```\n * @internal\n */\nexport function partition<T>(arr: T[], predicate: (item: T) => boolean): [T[], T[]] {\n\tconst satisfies: T[] = []\n\tconst doesNotSatisfy: T[] = []\n\tfor (const item of arr) {\n\t\tif (predicate(item)) {\n\t\t\tsatisfies.push(item)\n\t\t} else {\n\t\t\tdoesNotSatisfy.push(item)\n\t\t}\n\t}\n\treturn [satisfies, doesNotSatisfy]\n}\n\n/**\n * Check if two arrays are shallow equal.\n *\n * Compares two arrays for shallow equality by checking if they have the same length\n * and the same elements at each index using Object.is comparison. Returns true if arrays are\n * the same reference, have different lengths, or any elements differ.\n *\n * @param arr1 - First array to compare\n * @param arr2 - Second array to compare\n * @returns True if arrays are shallow equal, false otherwise\n *\n * @example\n * ```ts\n * areArraysShallowEqual([1, 2, 3], [1, 2, 3]) // true\n * areArraysShallowEqual([1, 2, 3], [1, 2, 4]) // false\n * areArraysShallowEqual(['a', 'b'], ['a', 'b']) // true\n * areArraysShallowEqual([1, 2], [1, 2, 3]) // false\n *\n * const obj = {x: 1}\n * areArraysShallowEqual([obj], [obj]) // true (same reference)\n * areArraysShallowEqual([{x: 1}], [{x: 1}]) // false (different objects)\n * ```\n * @internal\n */\nexport function areArraysShallowEqual<T>(arr1: readonly T[], arr2: readonly T[]): boolean {\n\tif (arr1 === arr2) return true\n\tif (arr1.length !== arr2.length) return false\n\tfor (let i = 0; i < arr1.length; i++) {\n\t\tif (!Object.is(arr1[i], arr2[i])) {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\n/**\n * Merge custom entries with defaults, replacing defaults that have matching keys.\n *\n * Combines two arrays by keeping all custom entries and only the default entries\n * that don't have a matching key in the custom entries. Custom entries always override defaults.\n * The result contains remaining defaults first, followed by all custom entries.\n *\n * @param key - The property name to use as the unique identifier\n * @param customEntries - Array of custom entries that will override defaults\n * @param defaults - Array of default entries\n * @returns A new array with defaults filtered out where custom entries exist, plus all custom entries\n *\n * @example\n * ```ts\n * const defaults = [{type: 'text', value: 'default'}, {type: 'number', value: 0}]\n * const custom = [{type: 'text', value: 'custom'}]\n *\n * mergeArraysAndReplaceDefaults('type', custom, defaults)\n * // Result: [{type: 'number', value: 0}, {type: 'text', value: 'custom'}]\n *\n * const tools = [{id: 'select', name: 'Select'}, {id: 'draw', name: 'Draw'}]\n * const customTools = [{id: 'select', name: 'Custom Select'}]\n *\n * mergeArraysAndReplaceDefaults('id', customTools, tools)\n * // Result: [{id: 'draw', name: 'Draw'}, {id: 'select', name: 'Custom Select'}]\n * ```\n * @internal\n */\nexport function mergeArraysAndReplaceDefaults<\n\tconst Key extends string,\n\tT extends { [K in Key]: string },\n>(key: Key, customEntries: readonly T[], defaults: readonly T[]) {\n\tconst overrideTypes = new Set(customEntries.map((entry) => entry[key]))\n\n\tconst result = []\n\tfor (const defaultEntry of defaults) {\n\t\tif (overrideTypes.has(defaultEntry[key])) continue\n\t\tresult.push(defaultEntry)\n\t}\n\n\tfor (const customEntry of customEntries) {\n\t\tresult.push(customEntry)\n\t}\n\n\treturn result\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmBO,SAAS,YAAe,KAAU,QAAqB;AAC7D,MAAI,IAAI,WAAW,EAAG,QAAO,CAAC;AAI9B,QAAM,oBAAqB,KAAK,IAAI,MAAM,IAAI,IAAI,SAAU,IAAI,UAAU,IAAI;AAG9E,SAAO,CAAC,GAAG,IAAI,MAAM,gBAAgB,GAAG,GAAG,IAAI,MAAM,GAAG,gBAAgB,CAAC;AAC1E;AAuBO,SAAS,OAAU,OAAY,QAA2C;AAChF,QAAM,SAAc,CAAC;AACrB,WAAU,YAAW,QAAQ,OAAO;AACnC,eAAW,YAAY,QAAQ;AAC9B,UAAI,SAAS,OAAO,MAAM,QAAQ,IAAI,SAAS,UAAU;AACxD,iBAAS;AAAA,MACV;AAAA,IACD;AACA,WAAO,KAAK,IAAI;AAAA,EACjB;AACA,SAAO;AACR;AAkBO,SAAS,QAAW,KAA4B;AACtD,SAAO,IAAI,OAAO,CAAC,MAAM,MAAM,UAAa,MAAM,IAAI;AACvD;AAmBO,SAAS,KAAQ,KAAkC;AACzD,SAAO,IAAI,IAAI,SAAS,CAAC;AAC1B;AAsBO,SAAS,MAAS,KAAmB,IAAwC;AACnF,MAAI;AACJ,MAAI,SAAS;AACb,aAAW,QAAQ,KAAK;AACvB,UAAM,MAAM,GAAG,IAAI;AACnB,QAAI,MAAM,QAAQ;AACjB,YAAM;AACN,eAAS;AAAA,IACV;AAAA,EACD;AACA,SAAO;AACR;AAsBO,SAAS,MAAS,KAAmB,IAAwC;AACnF,MAAI;AACJ,MAAI,SAAiB;AACrB,aAAW,QAAQ,KAAK;AACvB,UAAM,MAAM,GAAG,IAAI;AACnB,QAAI,MAAM,QAAQ;AACjB,YAAM;AACN,eAAS;AAAA,IACV;AAAA,EACD;AACA,SAAO;AACR;AAyBO,SAAS,UAAa,KAAU,WAA6C;AACnF,QAAM,YAAiB,CAAC;AACxB,QAAM,iBAAsB,CAAC;AAC7B,aAAW,QAAQ,KAAK;AACvB,QAAI,UAAU,IAAI,GAAG;AACpB,gBAAU,KAAK,IAAI;AAAA,IACpB,OAAO;AACN,qBAAe,KAAK,IAAI;AAAA,IACzB;AAAA,EACD;AACA,SAAO,CAAC,WAAW,cAAc;AAClC;AA0BO,SAAS,sBAAyB,MAAoB,MAA6B;AACzF,MAAI,SAAS,KAAM,QAAO;AAC1B,MAAI,KAAK,WAAW,KAAK,OAAQ,QAAO;AACxC,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACrC,QAAI,CAAC,OAAO,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG;AACjC,aAAO;AAAA,IACR;AAAA,EACD;AACA,SAAO;AACR;AA8BO,SAAS,8BAGd,KAAU,eAA6B,UAAwB;AAChE,QAAM,gBAAgB,IAAI,IAAI,cAAc,IAAI,CAAC,UAAU,MAAM,GAAG,CAAC,CAAC;AAEtE,QAAM,SAAS,CAAC;AAChB,aAAW,gBAAgB,UAAU;AACpC,QAAI,cAAc,IAAI,aAAa,GAAG,CAAC,EAAG;AAC1C,WAAO,KAAK,YAAY;AAAA,EACzB;AAEA,aAAW,eAAe,eAAe;AACxC,WAAO,KAAK,WAAW;AAAA,EACxB;AAEA,SAAO;AACR;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist-cjs/lib/bind.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/bind.ts"],
|
|
4
|
-
"sourcesContent": ["/*!\n * MIT License: https://github.com/NoHomey/bind-decorator/blob/master/License\n * Copyright (c) 2016 Ivo Stratev\n */\n\nimport { assert } from './control'\n\n/**\n *
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA,qBAAuB;AALvB;AAAA;AAAA;AAAA;
|
|
4
|
+
"sourcesContent": ["/*!\n * MIT License: https://github.com/NoHomey/bind-decorator/blob/master/License\n * Copyright (c) 2016 Ivo Stratev\n */\n\nimport { assert } from './control'\n\n/**\n * Decorator that binds a method to its class instance (legacy stage-2 TypeScript decorators).\n * When applied to a class method, ensures `this` always refers to the class instance,\n * even when the method is called as a callback or event handler.\n *\n * @param target - The prototype of the class being decorated\n * @param propertyKey - The name of the method being decorated\n * @param descriptor - The property descriptor for the method being decorated\n * @returns The modified property descriptor with bound method access\n * @example\n * ```typescript\n * class MyClass {\n * name = 'example';\n *\n * @bind\n * getName() {\n * return this.name;\n * }\n * }\n *\n * const instance = new MyClass();\n * const callback = instance.getName;\n * console.log(callback()); // 'example' (this is properly bound)\n * ```\n * @public\n */\nexport function bind<T extends (...args: any[]) => any>(\n\ttarget: object,\n\tpropertyKey: string,\n\tdescriptor: TypedPropertyDescriptor<T>\n): TypedPropertyDescriptor<T>\n\n/**\n * Decorator that binds a method to its class instance (TC39 decorators standard).\n * When applied to a class method, ensures `this` always refers to the class instance,\n * even when the method is called as a callback or event handler.\n *\n * @param originalMethod - The original method being decorated\n * @param context - The decorator context containing metadata about the method\n * @example\n * ```typescript\n * class EventHandler {\n * message = 'Hello World';\n *\n * @bind\n * handleClick() {\n * console.log(this.message);\n * }\n * }\n *\n * const handler = new EventHandler();\n * document.addEventListener('click', handler.handleClick); // 'this' is properly bound\n * ```\n * @public\n */\nexport function bind<This extends object, T extends (...args: any[]) => any>(\n\toriginalMethod: T,\n\tcontext: ClassMethodDecoratorContext<This, T>\n): void\n\n/**\n * Universal decorator implementation that handles both legacy stage-2 and TC39 decorator formats.\n * Automatically detects the decorator format based on the number of arguments and binds the\n * decorated method to the class instance, preventing common `this` context issues.\n *\n * @param args - Either legacy decorator arguments (target, propertyKey, descriptor) or TC39 decorator arguments (originalMethod, context)\n * @returns Property descriptor for legacy decorators, or void for TC39 decorators\n * @example\n * ```typescript\n * // Works with both decorator formats\n * class Calculator {\n * multiplier = 2;\n *\n * @bind\n * multiply(value: number) {\n * return value * this.multiplier;\n * }\n * }\n *\n * const calc = new Calculator();\n * const multiplyFn = calc.multiply;\n * console.log(multiplyFn(5)); // 10 (this.multiplier is accessible)\n *\n * // Useful for event handlers and callbacks\n * setTimeout(calc.multiply, 100, 3); // 6\n * ```\n * @public\n */\nexport function bind(\n\t...args: // legacy stage-2 typescript decorators\n\t| [_target: object, propertyKey: string, descriptor: PropertyDescriptor]\n\t\t// TC39 decorators\n\t\t| [originalMethod: (...args: any[]) => any, context: ClassMemberDecoratorContext]\n): PropertyDescriptor | void {\n\tif (args.length === 2) {\n\t\tconst [originalMethod, context] = args\n\t\tcontext.addInitializer(function initializeMethod(this: any) {\n\t\t\tassert(Reflect.isExtensible(this), 'Cannot bind to a non-extensible class.')\n\t\t\tconst value = originalMethod.bind(this)\n\t\t\tconst ok = Reflect.defineProperty(this, context.name, {\n\t\t\t\tvalue,\n\t\t\t\twritable: true,\n\t\t\t\tconfigurable: true,\n\t\t\t})\n\t\t\tassert(ok, 'Cannot bind a non-configurable class method.')\n\t\t})\n\t} else {\n\t\tconst [_target, propertyKey, descriptor] = args\n\t\tif (!descriptor || typeof descriptor.value !== 'function') {\n\t\t\tthrow new TypeError(\n\t\t\t\t`Only methods can be decorated with @bind. <${propertyKey}> is not a method!`\n\t\t\t)\n\t\t}\n\n\t\treturn {\n\t\t\tconfigurable: true,\n\t\t\tget(this: any): any {\n\t\t\t\tconst bound = descriptor.value!.bind(this)\n\t\t\t\t// Credits to https://github.com/andreypopp/autobind-decorator for memoizing the result of bind against a symbol on the instance.\n\t\t\t\tObject.defineProperty(this, propertyKey, {\n\t\t\t\t\tvalue: bound,\n\t\t\t\t\tconfigurable: true,\n\t\t\t\t\twritable: true,\n\t\t\t\t})\n\t\t\t\treturn bound\n\t\t\t},\n\t\t}\n\t}\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA,qBAAuB;AALvB;AAAA;AAAA;AAAA;AA+FO,SAAS,QACZ,MAIyB;AAC5B,MAAI,KAAK,WAAW,GAAG;AACtB,UAAM,CAAC,gBAAgB,OAAO,IAAI;AAClC,YAAQ,eAAe,SAAS,mBAA4B;AAC3D,iCAAO,QAAQ,aAAa,IAAI,GAAG,wCAAwC;AAC3E,YAAM,QAAQ,eAAe,KAAK,IAAI;AACtC,YAAM,KAAK,QAAQ,eAAe,MAAM,QAAQ,MAAM;AAAA,QACrD;AAAA,QACA,UAAU;AAAA,QACV,cAAc;AAAA,MACf,CAAC;AACD,iCAAO,IAAI,8CAA8C;AAAA,IAC1D,CAAC;AAAA,EACF,OAAO;AACN,UAAM,CAAC,SAAS,aAAa,UAAU,IAAI;AAC3C,QAAI,CAAC,cAAc,OAAO,WAAW,UAAU,YAAY;AAC1D,YAAM,IAAI;AAAA,QACT,8CAA8C,WAAW;AAAA,MAC1D;AAAA,IACD;AAEA,WAAO;AAAA,MACN,cAAc;AAAA,MACd,MAAoB;AACnB,cAAM,QAAQ,WAAW,MAAO,KAAK,IAAI;AAEzC,eAAO,eAAe,MAAM,aAAa;AAAA,UACxC,OAAO;AAAA,UACP,cAAc;AAAA,UACd,UAAU;AAAA,QACX,CAAC;AACD,eAAO;AAAA,MACR;AAAA,IACD;AAAA,EACD;AACD;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist-cjs/lib/cache.js
CHANGED
|
@@ -22,14 +22,36 @@ __export(cache_exports, {
|
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(cache_exports);
|
|
24
24
|
class WeakCache {
|
|
25
|
-
/**
|
|
25
|
+
/**
|
|
26
|
+
* The internal WeakMap storage for cached key-value pairs.
|
|
27
|
+
*
|
|
28
|
+
* @public
|
|
29
|
+
*/
|
|
26
30
|
items = /* @__PURE__ */ new WeakMap();
|
|
27
31
|
/**
|
|
28
|
-
* Get the cached value for a given
|
|
29
|
-
*
|
|
32
|
+
* Get the cached value for a given key, computing it if not already cached.
|
|
33
|
+
*
|
|
34
|
+
* Retrieves the cached value associated with the given key. If no cached
|
|
35
|
+
* value exists, calls the provided callback function to compute the value, stores it
|
|
36
|
+
* in the cache, and returns it. Subsequent calls with the same key will return the
|
|
37
|
+
* cached value without recomputation.
|
|
38
|
+
*
|
|
39
|
+
* @param item - The object key to retrieve the cached value for
|
|
40
|
+
* @param cb - Callback function that computes the value when not already cached
|
|
41
|
+
* @returns The cached value if it exists, otherwise the newly computed value from the callback
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```ts
|
|
45
|
+
* const cache = new WeakCache<HTMLElement, DOMRect>()
|
|
46
|
+
* const element = document.getElementById('my-element')!
|
|
47
|
+
*
|
|
48
|
+
* // First call computes and caches the bounding rect
|
|
49
|
+
* const rect1 = cache.get(element, (el) => el.getBoundingClientRect())
|
|
30
50
|
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
51
|
+
* // Second call returns cached value
|
|
52
|
+
* const rect2 = cache.get(element, (el) => el.getBoundingClientRect())
|
|
53
|
+
* // rect1 and rect2 are the same object
|
|
54
|
+
* ```
|
|
33
55
|
*/
|
|
34
56
|
get(item, cb) {
|
|
35
57
|
if (!this.items.has(item)) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/cache.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * A micro cache
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;
|
|
4
|
+
"sourcesContent": ["/**\n * A lightweight cache implementation using WeakMap for storing key-value pairs.\n *\n * A micro cache that stores computed values associated with object keys.\n * Uses WeakMap internally, which means keys can be garbage collected when no other\n * references exist, and only object keys are supported. Provides lazy computation\n * with memoization.\n *\n * @example\n * ```ts\n * const cache = new WeakCache<User, string>()\n * const user = { id: 1, name: 'Alice' }\n *\n * // Get cached value, computing it if not present\n * const displayName = cache.get(user, (u) => `${u.name} (#${u.id})`)\n * // Returns 'Alice (#1)'\n *\n * // Subsequent calls return cached value\n * const sameName = cache.get(user, (u) => `${u.name} (#${u.id})`)\n * // Returns 'Alice (#1)' without recomputing\n * ```\n * @public\n */\nexport class WeakCache<K extends object, V> {\n\t/**\n\t * The internal WeakMap storage for cached key-value pairs.\n\t *\n\t * @public\n\t */\n\titems = new WeakMap<K, V>()\n\n\t/**\n\t * Get the cached value for a given key, computing it if not already cached.\n\t *\n\t * Retrieves the cached value associated with the given key. If no cached\n\t * value exists, calls the provided callback function to compute the value, stores it\n\t * in the cache, and returns it. Subsequent calls with the same key will return the\n\t * cached value without recomputation.\n\t *\n\t * @param item - The object key to retrieve the cached value for\n\t * @param cb - Callback function that computes the value when not already cached\n\t * @returns The cached value if it exists, otherwise the newly computed value from the callback\n\t *\n\t * @example\n\t * ```ts\n\t * const cache = new WeakCache<HTMLElement, DOMRect>()\n\t * const element = document.getElementById('my-element')!\n\t *\n\t * // First call computes and caches the bounding rect\n\t * const rect1 = cache.get(element, (el) => el.getBoundingClientRect())\n\t *\n\t * // Second call returns cached value\n\t * const rect2 = cache.get(element, (el) => el.getBoundingClientRect())\n\t * // rect1 and rect2 are the same object\n\t * ```\n\t */\n\tget<P extends K>(item: P, cb: (item: P) => V) {\n\t\tif (!this.items.has(item)) {\n\t\t\tthis.items.set(item, cb(item))\n\t\t}\n\n\t\treturn this.items.get(item)!\n\t}\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAuBO,MAAM,UAA+B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAM3C,QAAQ,oBAAI,QAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA2B1B,IAAiB,MAAS,IAAoB;AAC7C,QAAI,CAAC,KAAK,MAAM,IAAI,IAAI,GAAG;AAC1B,WAAK,MAAM,IAAI,MAAM,GAAG,IAAI,CAAC;AAAA,IAC9B;AAEA,WAAO,KAAK,MAAM,IAAI,IAAI;AAAA,EAC3B;AACD;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist-cjs/lib/control.js
CHANGED
|
@@ -28,9 +28,21 @@ __export(control_exports, {
|
|
|
28
28
|
module.exports = __toCommonJS(control_exports);
|
|
29
29
|
var import_function = require("./function");
|
|
30
30
|
const Result = {
|
|
31
|
+
/**
|
|
32
|
+
* Create a successful result containing a value.
|
|
33
|
+
*
|
|
34
|
+
* @param value - The success value to wrap
|
|
35
|
+
* @returns An OkResult containing the value
|
|
36
|
+
*/
|
|
31
37
|
ok(value) {
|
|
32
38
|
return { ok: true, value };
|
|
33
39
|
},
|
|
40
|
+
/**
|
|
41
|
+
* Create a failed result containing an error.
|
|
42
|
+
*
|
|
43
|
+
* @param error - The error value to wrap
|
|
44
|
+
* @returns An ErrorResult containing the error
|
|
45
|
+
*/
|
|
34
46
|
err(error) {
|
|
35
47
|
return { ok: false, error };
|
|
36
48
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/control.ts"],
|
|
4
|
-
"sourcesContent": ["import { omitFromStackTrace } from './function'\n\n
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBAAmC;
|
|
4
|
+
"sourcesContent": ["import { omitFromStackTrace } from './function'\n\n/**\n * Represents a successful result containing a value.\n *\n * Interface for the success case of a Result type, containing the computed value.\n * Used in conjunction with ErrorResult to create a discriminated union for error handling.\n *\n * @example\n * ```ts\n * const success: OkResult<string> = { ok: true, value: 'Hello World' }\n * if (success.ok) {\n * console.log(success.value) // 'Hello World'\n * }\n * ```\n * @public\n */\nexport interface OkResult<T> {\n\treadonly ok: true\n\treadonly value: T\n}\n/**\n * Represents a failed result containing an error.\n *\n * Interface for the error case of a Result type, containing the error information.\n * Used in conjunction with OkResult to create a discriminated union for error handling.\n *\n * @example\n * ```ts\n * const failure: ErrorResult<string> = { ok: false, error: 'Something went wrong' }\n * if (!failure.ok) {\n * console.error(failure.error) // 'Something went wrong'\n * }\n * ```\n * @public\n */\nexport interface ErrorResult<E> {\n\treadonly ok: false\n\treadonly error: E\n}\n/**\n * A discriminated union type for handling success and error cases.\n *\n * Represents either a successful result with a value or a failed result with an error.\n * This pattern provides type-safe error handling without throwing exceptions. The 'ok' property\n * serves as the discriminant for type narrowing.\n *\n * @example\n * ```ts\n * function divide(a: number, b: number): Result<number, string> {\n * if (b === 0) {\n * return Result.err('Division by zero')\n * }\n * return Result.ok(a / b)\n * }\n *\n * const result = divide(10, 2)\n * if (result.ok) {\n * console.log(`Result: ${result.value}`) // Result: 5\n * } else {\n * console.error(`Error: ${result.error}`)\n * }\n * ```\n * @public\n */\nexport type Result<T, E> = OkResult<T> | ErrorResult<E>\n\n/**\n * Utility object for creating Result instances.\n *\n * Provides factory methods for creating OkResult and ErrorResult instances.\n * This is the preferred way to construct Result values for consistent structure.\n *\n * @example\n * ```ts\n * // Create success result\n * const success = Result.ok(42)\n * // success: OkResult<number> = { ok: true, value: 42 }\n *\n * // Create error result\n * const failure = Result.err('Invalid input')\n * // failure: ErrorResult<string> = { ok: false, error: 'Invalid input' }\n * ```\n * @public\n */\nexport const Result = {\n\t/**\n\t * Create a successful result containing a value.\n\t *\n\t * @param value - The success value to wrap\n\t * @returns An OkResult containing the value\n\t */\n\tok<T>(value: T): OkResult<T> {\n\t\treturn { ok: true, value }\n\t},\n\t/**\n\t * Create a failed result containing an error.\n\t *\n\t * @param error - The error value to wrap\n\t * @returns An ErrorResult containing the error\n\t */\n\terr<E>(error: E): ErrorResult<E> {\n\t\treturn { ok: false, error }\n\t},\n}\n\n/**\n * Throws an error for unhandled switch cases in exhaustive switch statements.\n *\n * Utility function to ensure exhaustive handling of discriminated unions in switch\n * statements. When called, it indicates a programming error where a case was not handled.\n * The TypeScript 'never' type ensures this function is only reachable if all cases aren't covered.\n *\n * @param value - The unhandled value (typed as 'never' for exhaustiveness checking)\n * @param property - Optional property name to extract from the value for better error messages\n * @returns Never returns (always throws)\n *\n * @example\n * ```ts\n * type Shape = 'circle' | 'square' | 'triangle'\n *\n * function getArea(shape: Shape): number {\n * switch (shape) {\n * case 'circle': return Math.PI * 5 * 5\n * case 'square': return 10 * 10\n * case 'triangle': return 0.5 * 10 * 8\n * default: return exhaustiveSwitchError(shape)\n * }\n * }\n * ```\n * @internal\n */\nexport function exhaustiveSwitchError(value: never, property?: string): never {\n\tconst debugValue =\n\t\tproperty && value && typeof value === 'object' && property in value ? value[property] : value\n\tthrow new Error(`Unknown switch case ${debugValue}`)\n}\n\n/**\n * Assert that a value is truthy, throwing an error if it's not.\n *\n * TypeScript assertion function that throws an error if the provided value is falsy.\n * After this function executes successfully, TypeScript narrows the type to exclude falsy values.\n * Stack trace is omitted from the error for cleaner debugging.\n *\n * @param value - The value to assert as truthy\n * @param message - Optional custom error message\n *\n * @example\n * ```ts\n * const user = getUser() // User | null\n * assert(user, 'User must be logged in')\n * // TypeScript now knows user is non-null\n * console.log(user.name) // Safe to access properties\n * ```\n * @internal\n */\nexport const assert: (value: unknown, message?: string) => asserts value = omitFromStackTrace(\n\t(value, message) => {\n\t\tif (!value) {\n\t\t\tthrow new Error(message || 'Assertion Error')\n\t\t}\n\t}\n)\n\n/**\n * Assert that a value is not null or undefined.\n *\n * Throws an error if the value is null or undefined, otherwise returns the value\n * with a refined type that excludes null and undefined. Stack trace is omitted for cleaner debugging.\n *\n * @param value - The value to check for null/undefined\n * @param message - Optional custom error message\n * @returns The value with null and undefined excluded from the type\n *\n * @example\n * ```ts\n * const element = document.getElementById('my-id') // HTMLElement | null\n * const safeElement = assertExists(element, 'Element not found')\n * // TypeScript now knows safeElement is HTMLElement (not null)\n * safeElement.addEventListener('click', handler) // Safe to call methods\n * ```\n * @internal\n */\nexport const assertExists = omitFromStackTrace(<T>(value: T, message?: string): NonNullable<T> => {\n\t// note that value == null is equivalent to value === null || value === undefined\n\tif (value == null) {\n\t\tthrow new Error(message ?? 'value must be defined')\n\t}\n\treturn value as NonNullable<T>\n})\n\n/**\n * Create a Promise with externally accessible resolve and reject functions.\n *\n * Creates a Promise along with its resolve and reject functions exposed as\n * properties on the returned object. This allows external code to control when the\n * Promise resolves or rejects, useful for coordination between async operations.\n *\n * @returns A Promise object with additional resolve and reject methods\n *\n * @example\n * ```ts\n * const deferred = promiseWithResolve<string>()\n *\n * // Set up the promise consumer\n * deferred.then(value => console.log(`Resolved: ${value}`))\n * deferred.catch(error => console.error(`Rejected: ${error}`))\n *\n * // Later, resolve from external code\n * setTimeout(() => {\n * deferred.resolve('Hello World')\n * }, 1000)\n * ```\n * @internal\n */\nexport function promiseWithResolve<T>(): Promise<T> & {\n\tresolve(value: T): void\n\treject(reason?: any): void\n} {\n\tlet resolve: (value: T) => void\n\tlet reject: (reason?: any) => void\n\tconst promise = new Promise<T>((res, rej) => {\n\t\tresolve = res\n\t\treject = rej\n\t})\n\treturn Object.assign(promise, {\n\t\tresolve: resolve!,\n\t\treject: reject!,\n\t})\n}\n\n/**\n * Create a Promise that resolves after a specified delay.\n *\n * Utility function for introducing delays in async code. Returns a Promise\n * that resolves with undefined after the specified number of milliseconds. Useful for\n * implementing timeouts, rate limiting, or adding delays in testing scenarios.\n *\n * @param ms - The delay in milliseconds\n * @returns A Promise that resolves after the specified delay\n *\n * @example\n * ```ts\n * async function delayedOperation() {\n * console.log('Starting...')\n * await sleep(1000) // Wait 1 second\n * console.log('Done!')\n * }\n *\n * // Can also be used with .then()\n * sleep(500).then(() => {\n * console.log('Half second has passed')\n * })\n * ```\n * @internal\n */\nexport function sleep(ms: number): Promise<void> {\n\t// eslint-disable-next-line no-restricted-globals\n\treturn new Promise((resolve) => setTimeout(resolve, ms))\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBAAmC;AAqF5B,MAAM,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOrB,GAAM,OAAuB;AAC5B,WAAO,EAAE,IAAI,MAAM,MAAM;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAO,OAA0B;AAChC,WAAO,EAAE,IAAI,OAAO,MAAM;AAAA,EAC3B;AACD;AA4BO,SAAS,sBAAsB,OAAc,UAA0B;AAC7E,QAAM,aACL,YAAY,SAAS,OAAO,UAAU,YAAY,YAAY,QAAQ,MAAM,QAAQ,IAAI;AACzF,QAAM,IAAI,MAAM,uBAAuB,UAAU,EAAE;AACpD;AAqBO,MAAM,aAA8D;AAAA,EAC1E,CAAC,OAAO,YAAY;AACnB,QAAI,CAAC,OAAO;AACX,YAAM,IAAI,MAAM,WAAW,iBAAiB;AAAA,IAC7C;AAAA,EACD;AACD;AAqBO,MAAM,mBAAe,oCAAmB,CAAI,OAAU,YAAqC;AAEjG,MAAI,SAAS,MAAM;AAClB,UAAM,IAAI,MAAM,WAAW,uBAAuB;AAAA,EACnD;AACA,SAAO;AACR,CAAC;AA0BM,SAAS,qBAGd;AACD,MAAI;AACJ,MAAI;AACJ,QAAM,UAAU,IAAI,QAAW,CAAC,KAAK,QAAQ;AAC5C,cAAU;AACV,aAAS;AAAA,EACV,CAAC;AACD,SAAO,OAAO,OAAO,SAAS;AAAA,IAC7B;AAAA,IACA;AAAA,EACD,CAAC;AACF;AA2BO,SAAS,MAAM,IAA2B;AAEhD,SAAO,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;AACxD;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/debounce.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n *
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;
|
|
4
|
+
"sourcesContent": ["/**\n * Create a debounced version of a function that delays execution until after a specified wait time.\n *\n * Debouncing ensures that a function is only executed once after a specified delay,\n * even if called multiple times in rapid succession. Each new call resets the timer. The debounced\n * function returns a Promise that resolves with the result of the original function. Includes a\n * cancel method to prevent execution if needed.\n *\n * @param callback - The function to debounce (can be sync or async)\n * @param wait - The delay in milliseconds before executing the function\n * @returns A debounced function that returns a Promise and includes a cancel method\n *\n * @example\n * ```ts\n * // Debounce a search function\n * const searchAPI = (query: string) => fetch(`/search?q=${query}`)\n * const debouncedSearch = debounce(searchAPI, 300)\n *\n * // Multiple rapid calls will only execute the last one after 300ms\n * debouncedSearch('react').then(result => console.log(result))\n * debouncedSearch('react hooks') // This cancels the previous call\n * debouncedSearch('react typescript') // Only this will execute\n *\n * // Cancel pending execution\n * debouncedSearch.cancel()\n *\n * // With async/await\n * const saveData = debounce(async (data: any) => {\n * return await api.save(data)\n * }, 1000)\n *\n * const result = await saveData({name: 'John'})\n * ```\n *\n * @public\n * @see source - https://gist.github.com/ca0v/73a31f57b397606c9813472f7493a940\n */\nexport function debounce<T extends unknown[], U>(\n\tcallback: (...args: T) => PromiseLike<U> | U,\n\twait: number\n) {\n\tlet state:\n\t\t| undefined\n\t\t| {\n\t\t\t\ttimeout: ReturnType<typeof setTimeout>\n\t\t\t\tpromise: Promise<U>\n\t\t\t\tresolve(value: U | PromiseLike<U>): void\n\t\t\t\treject(value: any): void\n\t\t\t\tlatestArgs: T\n\t\t } = undefined\n\n\tconst fn = (...args: T): Promise<U> => {\n\t\tif (!state) {\n\t\t\tstate = {} as any\n\t\t\tstate!.promise = new Promise((resolve, reject) => {\n\t\t\t\tstate!.resolve = resolve\n\t\t\t\tstate!.reject = reject\n\t\t\t})\n\t\t}\n\t\tclearTimeout(state!.timeout)\n\t\tstate!.latestArgs = args\n\t\t// It's up to the consumer of debounce to call `cancel`\n\t\t// eslint-disable-next-line no-restricted-globals\n\t\tstate!.timeout = setTimeout(() => {\n\t\t\tconst s = state!\n\t\t\tstate = undefined\n\t\t\ttry {\n\t\t\t\ts.resolve(callback(...s.latestArgs))\n\t\t\t} catch (e) {\n\t\t\t\ts.reject(e)\n\t\t\t}\n\t\t}, wait)\n\n\t\treturn state!.promise\n\t}\n\tfn.cancel = () => {\n\t\tif (!state) return\n\t\tclearTimeout(state.timeout)\n\t}\n\treturn fn\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAqCO,SAAS,SACf,UACA,MACC;AACD,MAAI,QAQG;AAEP,QAAM,KAAK,IAAI,SAAwB;AACtC,QAAI,CAAC,OAAO;AACX,cAAQ,CAAC;AACT,YAAO,UAAU,IAAI,QAAQ,CAAC,SAAS,WAAW;AACjD,cAAO,UAAU;AACjB,cAAO,SAAS;AAAA,MACjB,CAAC;AAAA,IACF;AACA,iBAAa,MAAO,OAAO;AAC3B,UAAO,aAAa;AAGpB,UAAO,UAAU,WAAW,MAAM;AACjC,YAAM,IAAI;AACV,cAAQ;AACR,UAAI;AACH,UAAE,QAAQ,SAAS,GAAG,EAAE,UAAU,CAAC;AAAA,MACpC,SAAS,GAAG;AACX,UAAE,OAAO,CAAC;AAAA,MACX;AAAA,IACD,GAAG,IAAI;AAEP,WAAO,MAAO;AAAA,EACf;AACA,KAAG,SAAS,MAAM;AACjB,QAAI,CAAC,MAAO;AACZ,iBAAa,MAAM,OAAO;AAAA,EAC3B;AACA,SAAO;AACR;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/error.ts"],
|
|
4
|
-
"sourcesContent": ["/** @public */\nexport interface ErrorAnnotations {\n\ttags: Record<string, number | string | boolean | bigint | symbol | null | undefined>\n\textras: Record<string, unknown>\n}\n\nconst annotationsByError = new WeakMap<object, ErrorAnnotations>()\n\n/**\n * Annotate an error with tags and additional data. Annotations won't overwrite existing ones.\n * Retrieve them with `getErrorAnnotations`.\n *\n * @internal\n */\nexport function annotateError(error: unknown, annotations: Partial<ErrorAnnotations>) {\n\tif (typeof error !== 'object' || error === null) return\n\n\tlet currentAnnotations = annotationsByError.get(error)\n\tif (!currentAnnotations) {\n\t\tcurrentAnnotations = { tags: {}, extras: {} }\n\t\tannotationsByError.set(error, currentAnnotations)\n\t}\n\n\tif (annotations.tags) {\n\t\tcurrentAnnotations.tags = {\n\t\t\t...currentAnnotations.tags,\n\t\t\t...annotations.tags,\n\t\t}\n\t}\n\tif (annotations.extras) {\n\t\tcurrentAnnotations.extras = {\n\t\t\t...currentAnnotations.extras,\n\t\t\t...annotations.extras,\n\t\t}\n\t}\n}\n\n
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAMA,MAAM,qBAAqB,oBAAI,QAAkC;
|
|
4
|
+
"sourcesContent": ["/** @public */\nexport interface ErrorAnnotations {\n\ttags: Record<string, number | string | boolean | bigint | symbol | null | undefined>\n\textras: Record<string, unknown>\n}\n\nconst annotationsByError = new WeakMap<object, ErrorAnnotations>()\n\n/**\n * Annotate an error with tags and additional data. Annotations won't overwrite existing ones.\n * Retrieve them with `getErrorAnnotations`.\n *\n * @param error - The error object to annotate\n * @param annotations - Partial annotations to add (tags and/or extras)\n * @returns void\n * @example\n * ```ts\n * const error = new Error('Something went wrong')\n * annotateError(error, {\n * tags: { userId: '123', operation: 'save' },\n * extras: { timestamp: Date.now() }\n * })\n * ```\n *\n * @internal\n */\nexport function annotateError(error: unknown, annotations: Partial<ErrorAnnotations>) {\n\tif (typeof error !== 'object' || error === null) return\n\n\tlet currentAnnotations = annotationsByError.get(error)\n\tif (!currentAnnotations) {\n\t\tcurrentAnnotations = { tags: {}, extras: {} }\n\t\tannotationsByError.set(error, currentAnnotations)\n\t}\n\n\tif (annotations.tags) {\n\t\tcurrentAnnotations.tags = {\n\t\t\t...currentAnnotations.tags,\n\t\t\t...annotations.tags,\n\t\t}\n\t}\n\tif (annotations.extras) {\n\t\tcurrentAnnotations.extras = {\n\t\t\t...currentAnnotations.extras,\n\t\t\t...annotations.extras,\n\t\t}\n\t}\n}\n\n/**\n * Retrieve annotations that have been added to an error object.\n *\n * @param error - The error object to get annotations from\n * @returns The error annotations (tags and extras) or empty objects if none exist\n * @example\n * ```ts\n * const error = new Error('Something went wrong')\n * annotateError(error, { tags: { userId: '123' } })\n * const annotations = getErrorAnnotations(error)\n * console.log(annotations.tags.userId) // '123'\n * ```\n *\n * @internal\n */\nexport function getErrorAnnotations(error: Error): ErrorAnnotations {\n\treturn annotationsByError.get(error) ?? { tags: {}, extras: {} }\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAMA,MAAM,qBAAqB,oBAAI,QAAkC;AAoB1D,SAAS,cAAc,OAAgB,aAAwC;AACrF,MAAI,OAAO,UAAU,YAAY,UAAU,KAAM;AAEjD,MAAI,qBAAqB,mBAAmB,IAAI,KAAK;AACrD,MAAI,CAAC,oBAAoB;AACxB,yBAAqB,EAAE,MAAM,CAAC,GAAG,QAAQ,CAAC,EAAE;AAC5C,uBAAmB,IAAI,OAAO,kBAAkB;AAAA,EACjD;AAEA,MAAI,YAAY,MAAM;AACrB,uBAAmB,OAAO;AAAA,MACzB,GAAG,mBAAmB;AAAA,MACtB,GAAG,YAAY;AAAA,IAChB;AAAA,EACD;AACA,MAAI,YAAY,QAAQ;AACvB,uBAAmB,SAAS;AAAA,MAC3B,GAAG,mBAAmB;AAAA,MACtB,GAAG,YAAY;AAAA,IAChB;AAAA,EACD;AACD;AAiBO,SAAS,oBAAoB,OAAgC;AACnE,SAAO,mBAAmB,IAAI,KAAK,KAAK,EAAE,MAAM,CAAC,GAAG,QAAQ,CAAC,EAAE;AAChE;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|