@softsky/utils 2.5.5 → 2.6.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.
package/README.md CHANGED
@@ -150,7 +150,7 @@ __function__ `createThrottledFunction` - Create throttled function. Basically li
150
150
 
151
151
  ---
152
152
  __function__ `createDelayedFunction` - Create debounced function. Basically create function that will be called with delay,
153
- but if another call comes in, we reset the timer.
153
+ but if another call comes in, we reset the timer (previous function isn't called).
154
154
 
155
155
  ---
156
156
  __class__ `ImmediatePromise` - Promise that accepts no callback, but exposes `resolve` and `reject` methods
@@ -158,6 +158,9 @@ __class__ `ImmediatePromise` - Promise that accepts no callback, but exposes `re
158
158
  ---
159
159
  __function__ `wait` - setTimeout promisify
160
160
 
161
+ ---
162
+ __function__ `timeout` - Reject after specified time
163
+
161
164
  ---
162
165
  __function__ `noop` - Empty function that does nothing
163
166
 
@@ -167,6 +170,37 @@ __async function__ `concurrentRun` - Run array of async tasks concurrently
167
170
  ---
168
171
  __class__ `SimpleEventSource` - Create simple event source. Consider using `signal()` for reactive state managment.
169
172
 
173
+ ---
174
+ __class__ `Semaphore` - Semaphore is used to limit concurrent tasks by delaying promise.
175
+
176
+ ```ts
177
+ const semaphore = new Semaphore(2);
178
+
179
+ async function task() {
180
+ await semaphore.acquire();
181
+ try {
182
+ // This code can only be executed by two tasks at the same time
183
+ } finally {
184
+ semaphore.release();
185
+ }
186
+ }
187
+ task();
188
+ task();
189
+ task(); // This task will wait until one of the previous tasks releases the semaphore.
190
+
191
+ // === SHORTHAND ===
192
+ semaphore.run(()=>{
193
+ // Your code
194
+ })
195
+ semaphore.run(()=>{
196
+ // Your code
197
+ })
198
+ // ...
199
+ ```
200
+
201
+ ---
202
+ __async function__ `withTimeout` - Add timeout to a promise
203
+
170
204
  ---
171
205
 
172
206
 
@@ -175,6 +209,9 @@ Custom errors, finding errors and error handling.
175
209
 
176
210
  __class__ `ValidationError` - Use as intended error. Basically 4** errors in HTTP
177
211
 
212
+ ---
213
+ __class__ `TimeoutError` - Use as intended error. Basically 4** errors in HTTP
214
+
178
215
  ---
179
216
  __function__ `findErrorText` - Find error inside anything recursively.
180
217
  Good for finding human-readable errors.
@@ -274,6 +311,27 @@ __function__ `factorial` - Factorial
274
311
  ---
275
312
  __function__ `fib` - Fibonacci
276
313
 
314
+ ---
315
+ __function__ `clamp` - Clamp numbers to max and min
316
+
317
+ ---
318
+ __function__ `inRange` - Is number in range. Inclusive.
319
+
320
+ ---
321
+ __function__ `mean` - Calucalate avarage from array of numbers
322
+
323
+ ---
324
+ __function__ `round` - Round with precision.
325
+
326
+ ```ts
327
+ round(1.2345); // 1
328
+ round(1.2345, 2); // 1.23
329
+ round(1.2345, 10); // 1.2345
330
+ ```
331
+
332
+ ---
333
+ __function__ `sum` - Sum of array of numbers
334
+
277
335
  ---
278
336
 
279
337
 
@@ -352,7 +410,7 @@ Effects are simplest way to react to signal changes.
352
410
  Returned data from handler function will be passed to it on next signal change.
353
411
  Returns a function that will clear the effect.
354
412
 
355
- ```ts
413
+
356
414
  // Will print signal on change
357
415
  effect(()=>{
358
416
  console.log($mySignal())
@@ -363,7 +421,6 @@ const mySignal = $mySignal()
363
421
  if(last>mySignal) console.log('Increment!')
364
422
  return mySignal;
365
423
  })
366
- ```
367
424
 
368
425
  ---
369
426
  __function__ `untrack` - __SIGNALS SYSTEM__
@@ -513,19 +570,16 @@ __type__ `Concat` - Concat types of array or objects
513
570
 
514
571
  ---
515
572
  __type__ `Prettify` - Visual only overhaul. Shows final type result on hover.
573
+
516
574
  ```ts
517
575
  type a = {a: '1'}
518
576
  type b = Prettify<a & { b: 'b' }>
519
- ```
520
- On hovering b it will show
521
- ```ts
577
+ // On hovering b it will show
522
578
  type b = {
523
579
  a: "1";
524
580
  b: "b";
525
581
  }
526
- ```
527
- instead of
528
- ```ts
582
+ // instead of
529
583
  type b = a & {
530
584
  b: "b";
531
585
  }
package/dist/control.d.ts CHANGED
@@ -26,7 +26,7 @@ export declare function extractUUIDDate(uuid: string): Date;
26
26
  * hash
27
27
  * ]
28
28
  */
29
- export declare function createCashedFunction<T, V extends JSONSerializable[]>(function_: (...arguments_: V) => T): readonly [(...arguments_: V) => T, (...arguments_: V) => boolean, Map<string, T>];
29
+ export declare function createCashedFunction<T, V extends JSONSerializable[]>(run: (...data: V) => T): readonly [(...data: V) => T, (...data: V) => boolean, Map<string, T>];
30
30
  /**
31
31
  * Creates cached function. All arguments/results are cached. Will store in cache resolved data.
32
32
  * Returns [
@@ -35,16 +35,16 @@ export declare function createCashedFunction<T, V extends JSONSerializable[]>(fu
35
35
  * hash
36
36
  * ]
37
37
  */
38
- export declare function createCashedAsyncFunction<T, V extends JSONSerializable[]>(function_: (...arguments_: V) => Promise<T>): readonly [(...arguments_: V) => Promise<T>, (...arguments_: V) => boolean, Map<string, T>];
38
+ export declare function createCashedAsyncFunction<T, V extends JSONSerializable[]>(run: (...data: V) => Promise<T>): readonly [(...data: V) => Promise<T>, (...data: V) => boolean, Map<string, T>];
39
39
  /** Retry async function */
40
- export declare function retry<T>(function_: () => Promise<T>, retries?: number, interval?: number | number[], ignore?: (error: unknown) => boolean): Promise<T>;
40
+ export declare function retry<T>(run: () => Promise<T>, retries?: number, interval?: number | number[], ignore?: (error: unknown) => boolean): Promise<T>;
41
41
  /** Create debounced function. Basically adds cooldown to function. Warning: throws! */
42
- export declare function createDebouncedFunction<T, V extends unknown[]>(function_: (...arguments_: V) => T, time: number): (...arguments_: V) => T;
42
+ export declare function createDebouncedFunction<T, V extends unknown[]>(run: (...data: V) => T, time: number): (...data: V) => T;
43
43
  /** Create throttled function. Basically limits function calls in time period. Warning: throws! */
44
- export declare function createThrottledFunction<T, V extends unknown[]>(function_: (...arguments_: V) => T, calls: number, time: number): (...arguments_: V) => T;
44
+ export declare function createThrottledFunction<T, V extends unknown[]>(run: (...data: V) => T, calls: number, time: number): (...data: V) => T;
45
45
  /** Create debounced function. Basically create function that will be called with delay,
46
- * but if another call comes in, we reset the timer. */
47
- export declare function createDelayedFunction<T, V extends unknown[]>(function_: (...arguments_: V) => T, time: number): (...arguments_: V) => Promise<T>;
46
+ * but if another call comes in, we reset the timer (previous function isn't called). */
47
+ export declare function createDelayedFunction<T, V extends unknown[]>(run: (...data: V) => T, time: number): (...data: V) => Promise<T>;
48
48
  type ResolveFunction<T> = undefined extends T ? (value?: T | PromiseLike<T>) => void : (value: T | PromiseLike<T>) => void;
49
49
  /** Promise that accepts no callback, but exposes `resolve` and `reject` methods */
50
50
  export declare class ImmediatePromise<T> extends Promise<T> {
@@ -56,6 +56,8 @@ export declare class ImmediatePromise<T> extends Promise<T> {
56
56
  export default function deepPromiseAll<T>(input: T): Promise<AwaitedObject<T>>;
57
57
  /** setTimeout promisify */
58
58
  export declare function wait(time: number): Promise<unknown>;
59
+ /** Reject after specified time */
60
+ export declare function timeout(time: number): Promise<never>;
59
61
  /** Empty function that does nothing */
60
62
  export declare function noop(): void;
61
63
  /** Run array of async tasks concurrently */
@@ -75,4 +77,50 @@ export declare class SimpleEventSource<EVENTS extends Record<string, unknown>> {
75
77
  off: <T extends keyof EVENTS>(name: T, handler: (data: EVENTS[T]) => unknown) => void;
76
78
  };
77
79
  }
80
+ /**
81
+ * Semaphore is used to limit concurrent tasks by delaying promise.
82
+ *
83
+ * ```ts
84
+ * const semaphore = new Semaphore(2);
85
+ *
86
+ * async function task() {
87
+ * await semaphore.acquire();
88
+ * try {
89
+ * // This code can only be executed by two tasks at the same time
90
+ * } finally {
91
+ * semaphore.release();
92
+ * }
93
+ * }
94
+ * task();
95
+ * task();
96
+ * task(); // This task will wait until one of the previous tasks releases the semaphore.
97
+ *
98
+ * // === SHORTHAND ===
99
+ * semaphore.run(()=>{
100
+ * // Your code
101
+ * })
102
+ * semaphore.run(()=>{
103
+ * // Your code
104
+ * })
105
+ * // ...
106
+ * ```
107
+ */
108
+ export declare class Semaphore {
109
+ /** The maximum number of concurrent operations allowed.*/
110
+ capacity: number;
111
+ /** Tasks running. */
112
+ running: number;
113
+ protected deferredTasks: (() => void)[];
114
+ constructor(
115
+ /** The maximum number of concurrent operations allowed.*/
116
+ capacity: number);
117
+ /** Acquires a semaphore, blocking if necessary until one is available. */
118
+ acquire(): Promise<void>;
119
+ /** Releases a semaphore, allowing one more operation to proceed. */
120
+ release(): void;
121
+ /** Shorthand for running functions */
122
+ run<T>(run: () => T): Promise<T>;
123
+ }
124
+ /** Add timeout to a promise */
125
+ export declare function withTimeout<T>(run: () => Promise<T>, ms: number): Promise<T>;
78
126
  export {};
package/dist/control.js CHANGED
@@ -2,6 +2,7 @@
2
2
  * Utils related to code execution flow.
3
3
  */
4
4
  import { removeFromArray } from './arrays';
5
+ import { DelayedError, TimeoutError } from './errors';
5
6
  let lastIncId = Math.floor(Math.random() * 0x1_00_00);
6
7
  /** Id generated only once per session */
7
8
  export const SESSION_ID = Math.floor(Math.random() * 0x10_00_00_00_00_00_00)
@@ -38,19 +39,19 @@ export function extractUUIDDate(uuid) {
38
39
  * hash
39
40
  * ]
40
41
  */
41
- export function createCashedFunction(function_) {
42
+ export function createCashedFunction(run) {
42
43
  const hash = new Map();
43
44
  return [
44
- (...arguments_) => {
45
- const key = JSON.stringify(arguments_);
45
+ (...data) => {
46
+ const key = JSON.stringify(data);
46
47
  const value = hash.get(key);
47
48
  if (value)
48
49
  return value;
49
- const newValue = function_(...arguments_);
50
+ const newValue = run(...data);
50
51
  hash.set(key, newValue);
51
52
  return newValue;
52
53
  },
53
- (...arguments_) => hash.delete(JSON.stringify(arguments_)),
54
+ (...data) => hash.delete(JSON.stringify(data)),
54
55
  hash,
55
56
  ];
56
57
  }
@@ -62,26 +63,26 @@ export function createCashedFunction(function_) {
62
63
  * hash
63
64
  * ]
64
65
  */
65
- export function createCashedAsyncFunction(function_) {
66
+ export function createCashedAsyncFunction(run) {
66
67
  const hash = new Map();
67
68
  return [
68
- async (...arguments_) => {
69
- const key = JSON.stringify(arguments_);
69
+ async (...data) => {
70
+ const key = JSON.stringify(data);
70
71
  const value = hash.get(key);
71
72
  if (value)
72
73
  return value;
73
- const newValue = await function_(...arguments_);
74
+ const newValue = await run(...data);
74
75
  hash.set(key, newValue);
75
76
  return newValue;
76
77
  },
77
- (...arguments_) => hash.delete(JSON.stringify(arguments_)),
78
+ (...data) => hash.delete(JSON.stringify(data)),
78
79
  hash,
79
80
  ];
80
81
  }
81
82
  /** Retry async function */
82
- export async function retry(function_, retries = 5, interval = 0, ignore) {
83
+ export async function retry(run, retries = 5, interval = 0, ignore) {
83
84
  try {
84
- return await function_();
85
+ return await run();
85
86
  }
86
87
  catch (error) {
87
88
  if (retries === 0 || ignore?.(error))
@@ -89,46 +90,46 @@ export async function retry(function_, retries = 5, interval = 0, ignore) {
89
90
  await wait(typeof interval === 'number'
90
91
  ? interval
91
92
  : interval[interval.length - retries]);
92
- return retry(function_, retries - 1, interval);
93
+ return retry(run, retries - 1, interval);
93
94
  }
94
95
  }
95
96
  /** Create debounced function. Basically adds cooldown to function. Warning: throws! */
96
- export function createDebouncedFunction(function_, time) {
97
+ export function createDebouncedFunction(run, time) {
97
98
  let nextExec = 0;
98
- return (...arguments_) => {
99
+ return (...data) => {
99
100
  const now = Date.now();
100
101
  if (nextExec > now)
101
- throw new Error('Debounced');
102
+ throw new DelayedError();
102
103
  nextExec = now + time;
103
- return function_(...arguments_);
104
+ return run(...data);
104
105
  };
105
106
  }
106
107
  /** Create throttled function. Basically limits function calls in time period. Warning: throws! */
107
- export function createThrottledFunction(function_, calls, time) {
108
+ export function createThrottledFunction(run, calls, time) {
108
109
  let nextClear = 0;
109
110
  let amount = 0;
110
- return (...arguments_) => {
111
+ return (...data) => {
111
112
  const now = Date.now();
112
113
  if (nextClear <= now) {
113
114
  nextClear = now + time;
114
115
  amount = 0;
115
116
  }
116
117
  if (amount === calls)
117
- throw new Error('Throttled');
118
+ throw new DelayedError();
118
119
  amount++;
119
- return function_(...arguments_);
120
+ return run(...data);
120
121
  };
121
122
  }
122
123
  /** Create debounced function. Basically create function that will be called with delay,
123
- * but if another call comes in, we reset the timer. */
124
- export function createDelayedFunction(function_, time) {
124
+ * but if another call comes in, we reset the timer (previous function isn't called). */
125
+ export function createDelayedFunction(run, time) {
125
126
  let timeout;
126
127
  let activePromise;
127
- return (...arguments_) => {
128
+ return (...data) => {
128
129
  activePromise ??= new ImmediatePromise();
129
130
  clearTimeout(timeout);
130
131
  timeout = setTimeout(() => {
131
- activePromise?.resolve(function_(...arguments_));
132
+ activePromise?.resolve(run(...data));
132
133
  activePromise = undefined;
133
134
  }, time);
134
135
  return activePromise;
@@ -169,37 +170,19 @@ export default async function deepPromiseAll(input) {
169
170
  export function wait(time) {
170
171
  return new Promise((r) => setTimeout(r, time));
171
172
  }
173
+ /** Reject after specified time */
174
+ export function timeout(time) {
175
+ return new Promise((_, reject) => setTimeout(() => {
176
+ reject(new TimeoutError());
177
+ }, time));
178
+ }
172
179
  /** Empty function that does nothing */
173
180
  // eslint-disable-next-line @typescript-eslint/no-empty-function
174
181
  export function noop() { }
175
182
  /** Run array of async tasks concurrently */
176
183
  export async function concurrentRun(tasks, concurrency = 4) {
177
- return new Promise((resolve, reject) => {
178
- const results = new Array(tasks.length);
179
- let inProgress = 0;
180
- let index = 0;
181
- let completed = 0;
182
- function runNext() {
183
- if (completed === tasks.length) {
184
- resolve(results);
185
- return;
186
- }
187
- while (inProgress < concurrency && index < tasks.length) {
188
- const currentIndex = index++;
189
- const task = tasks[currentIndex];
190
- inProgress++;
191
- task()
192
- .then((result) => {
193
- results[currentIndex] = result;
194
- inProgress--;
195
- completed++;
196
- runNext();
197
- })
198
- .catch(reject);
199
- }
200
- }
201
- runNext();
202
- });
184
+ const semaphore = new Semaphore(concurrency);
185
+ return Promise.all(tasks.map(semaphore.run.bind(semaphore)));
203
186
  }
204
187
  /** Create simple event source. Consider using `signal()` for reactive state managment. */
205
188
  export class SimpleEventSource {
@@ -239,3 +222,69 @@ export class SimpleEventSource {
239
222
  };
240
223
  }
241
224
  }
225
+ /**
226
+ * Semaphore is used to limit concurrent tasks by delaying promise.
227
+ *
228
+ * ```ts
229
+ * const semaphore = new Semaphore(2);
230
+ *
231
+ * async function task() {
232
+ * await semaphore.acquire();
233
+ * try {
234
+ * // This code can only be executed by two tasks at the same time
235
+ * } finally {
236
+ * semaphore.release();
237
+ * }
238
+ * }
239
+ * task();
240
+ * task();
241
+ * task(); // This task will wait until one of the previous tasks releases the semaphore.
242
+ *
243
+ * // === SHORTHAND ===
244
+ * semaphore.run(()=>{
245
+ * // Your code
246
+ * })
247
+ * semaphore.run(()=>{
248
+ * // Your code
249
+ * })
250
+ * // ...
251
+ * ```
252
+ */
253
+ export class Semaphore {
254
+ capacity;
255
+ /** Tasks running. */
256
+ running = 0;
257
+ deferredTasks = [];
258
+ constructor(
259
+ /** The maximum number of concurrent operations allowed.*/
260
+ capacity) {
261
+ this.capacity = capacity;
262
+ }
263
+ /** Acquires a semaphore, blocking if necessary until one is available. */
264
+ async acquire() {
265
+ if (this.running === this.capacity)
266
+ return new Promise((resolve) => {
267
+ this.deferredTasks.push(resolve);
268
+ });
269
+ this.running++;
270
+ }
271
+ /** Releases a semaphore, allowing one more operation to proceed. */
272
+ release() {
273
+ this.running--;
274
+ this.deferredTasks.shift()?.();
275
+ }
276
+ /** Shorthand for running functions */
277
+ async run(run) {
278
+ await this.acquire();
279
+ try {
280
+ return await run();
281
+ }
282
+ finally {
283
+ this.release();
284
+ }
285
+ }
286
+ }
287
+ /** Add timeout to a promise */
288
+ export async function withTimeout(run, ms) {
289
+ return Promise.race([run(), timeout(ms)]);
290
+ }
package/dist/errors.d.ts CHANGED
@@ -7,6 +7,17 @@
7
7
  export declare class ValidationError extends Error {
8
8
  name: string;
9
9
  }
10
+ /**
11
+ * Use as intended error. Basically 4** errors in HTTP
12
+ */
13
+ export declare class TimeoutError extends Error {
14
+ name: string;
15
+ constructor();
16
+ }
17
+ export declare class DelayedError extends Error {
18
+ name: string;
19
+ constructor();
20
+ }
10
21
  /**
11
22
  * Find error inside anything recursively.
12
23
  * Good for finding human-readable errors.
package/dist/errors.js CHANGED
@@ -8,6 +8,21 @@ import { getPropertyNames } from './objects';
8
8
  export class ValidationError extends Error {
9
9
  name = 'ValidationError';
10
10
  }
11
+ /**
12
+ * Use as intended error. Basically 4** errors in HTTP
13
+ */
14
+ export class TimeoutError extends Error {
15
+ name = 'TimeoutError';
16
+ constructor() {
17
+ super('The operation has timed out');
18
+ }
19
+ }
20
+ export class DelayedError extends Error {
21
+ name = 'DelayedError';
22
+ constructor() {
23
+ super('The operation is delayed and can not be executed now');
24
+ }
25
+ }
11
26
  const defaultPriorityErrorKeys = [
12
27
  'message',
13
28
  'messages',
package/dist/numbers.d.ts CHANGED
@@ -8,3 +8,21 @@ export declare function parseFloat(parameter: unknown): number;
8
8
  export declare function factorial(n: number): number;
9
9
  /** Fibonacci */
10
10
  export declare function fib(n: number): bigint;
11
+ /** Clamp numbers to max and min */
12
+ export declare function clamp(value: number, min?: number, max?: number): number;
13
+ /** Is number in range. Inclusive. */
14
+ export declare function inRange(value: number, min?: number, max?: number): boolean;
15
+ /** Calucalate avarage from array of numbers */
16
+ export declare function mean(array: number[]): number;
17
+ /**
18
+ * Round with precision.
19
+ *
20
+ * ```ts
21
+ * round(1.2345); // 1
22
+ * round(1.2345, 2); // 1.23
23
+ * round(1.2345, 10); // 1.2345
24
+ * ```
25
+ */
26
+ export declare function round(value: number, precision?: number): number;
27
+ /** Sum of array of numbers */
28
+ export declare function sum(array: number[]): number;
package/dist/numbers.js CHANGED
@@ -4,8 +4,8 @@
4
4
  import { ValidationError } from './errors';
5
5
  /** Random number between min and max. May enable float */
6
6
  export function random(min, max, float) {
7
- const number_ = Math.random() * (max - min) + min;
8
- return float ? number_ : Math.round(number_);
7
+ const number = Math.random() * (max - min) + min;
8
+ return float ? number : Math.round(number);
9
9
  }
10
10
  /** Same as Number.parseInt but throws if NaN or not safe */
11
11
  export function parseInt(parameter, radix) {
@@ -44,3 +44,42 @@ export function fib(n) {
44
44
  }
45
45
  return a;
46
46
  }
47
+ /** Clamp numbers to max and min */
48
+ export function clamp(value, min = -Infinity, max = Infinity) {
49
+ if (value > max)
50
+ return max;
51
+ if (value < min)
52
+ return min;
53
+ return value;
54
+ }
55
+ /** Is number in range. Inclusive. */
56
+ export function inRange(value, min = -Infinity, max = Infinity) {
57
+ return value <= max && value >= min;
58
+ }
59
+ /** Calucalate avarage from array of numbers */
60
+ export function mean(array) {
61
+ let sum = 0;
62
+ for (let index = 0; index < array.length; index++)
63
+ sum += array[index];
64
+ return sum / array.length;
65
+ }
66
+ /**
67
+ * Round with precision.
68
+ *
69
+ * ```ts
70
+ * round(1.2345); // 1
71
+ * round(1.2345, 2); // 1.23
72
+ * round(1.2345, 10); // 1.2345
73
+ * ```
74
+ */
75
+ export function round(value, precision = 0) {
76
+ const mult = 10 ** precision;
77
+ return Math.round(value * mult) / mult;
78
+ }
79
+ /** Sum of array of numbers */
80
+ export function sum(array) {
81
+ let result = 0;
82
+ for (let index = 0; index < array.length; index++)
83
+ result += array[index];
84
+ return result;
85
+ }
package/dist/objects.d.ts CHANGED
@@ -1,15 +1,15 @@
1
1
  /**
2
2
  * [object Object]
3
3
  */
4
- import { Constructor, ObjectAddPrefix } from './types';
4
+ import { AnyFunction, Constructor, ObjectAddPrefix } from './types';
5
5
  /** Get all prorerty names, including in prototype */
6
6
  export declare function getPropertyNames(object: object, keys?: Set<unknown>): Set<unknown>;
7
7
  /** Map function like for arrays, but for objects */
8
- export declare function objectMap<T extends object>(object: T, function_: (key: keyof T, value: T[keyof T]) => [string, unknown]): {
8
+ export declare function objectMap<T extends object>(object: T, run: (key: keyof T, value: T[keyof T]) => [string, unknown]): {
9
9
  [k: string]: unknown;
10
10
  };
11
11
  /** Filter function like for arrays, but for objects */
12
- export declare function objectFilter<T extends object>(object: T, function_: (key: keyof T, value: T[keyof T]) => unknown): {
12
+ export declare function objectFilter<T extends object>(object: T, run: (key: keyof T, value: T[keyof T]) => unknown): {
13
13
  [k: string]: any;
14
14
  };
15
15
  /** Adds prefix to every key in object */
@@ -45,12 +45,36 @@ export declare function pick<T extends object, K extends keyof T>(object: T, key
45
45
  * ```
46
46
  */
47
47
  export declare class Base {
48
+ /** Id of last AUTOMATICALLY created object id */
48
49
  static lastId: number;
50
+ /** Map of class instances by they ids */
49
51
  static idMap: Map<number, Base>;
52
+ /** Map of subclasses of base class by their name */
50
53
  static subclasses: Map<string, Constructor<Base>>;
54
+ /** Functions in this array will be run on instance destroy */
55
+ runOnDestroy: AnyFunction[];
51
56
  private _id;
52
57
  get id(): number;
53
58
  set id(value: number);
54
59
  constructor(id?: number);
60
+ /**
61
+ * Include next lines when extending this class:
62
+ * ```js
63
+ * static {
64
+ * this.registerSubclass()
65
+ * }
66
+ * ```
67
+ */
55
68
  static registerSubclass(): void;
69
+ /**
70
+ * Destroy instance. Will run all `runOnDestroy` functions
71
+ * and remove istance from idMap.
72
+ * If class is garbage collected automatically runs this.
73
+ * */
74
+ destroy(): void;
75
+ /**
76
+ * Register autocleared event handler.
77
+ * If using classes methods don't forget to `bind(this)`
78
+ */
79
+ protected registerEvent(target: EventTarget, type: string, listener: EventListener, options?: AddEventListenerOptions): void;
56
80
  }
package/dist/objects.js CHANGED
@@ -12,12 +12,12 @@ export function getPropertyNames(object, keys = new Set()) {
12
12
  return keys;
13
13
  }
14
14
  /** Map function like for arrays, but for objects */
15
- export function objectMap(object, function_) {
16
- return Object.fromEntries(Object.entries(object).map(([key, value]) => function_(key, value)));
15
+ export function objectMap(object, run) {
16
+ return Object.fromEntries(Object.entries(object).map(([key, value]) => run(key, value)));
17
17
  }
18
18
  /** Filter function like for arrays, but for objects */
19
- export function objectFilter(object, function_) {
20
- return Object.fromEntries(Object.entries(object).filter(([key, value]) => function_(key, value)));
19
+ export function objectFilter(object, run) {
20
+ return Object.fromEntries(Object.entries(object).filter(([key, value]) => run(key, value)));
21
21
  }
22
22
  /** Adds prefix to every key in object */
23
23
  export function addPrefixToObject(object, prefix) {
@@ -118,9 +118,14 @@ export function pick(object, keys) {
118
118
  * ```
119
119
  */
120
120
  export class Base {
121
+ /** Id of last AUTOMATICALLY created object id */
121
122
  static lastId = 0;
123
+ /** Map of class instances by they ids */
122
124
  static idMap = new Map();
125
+ /** Map of subclasses of base class by their name */
123
126
  static subclasses = new Map();
127
+ /** Functions in this array will be run on instance destroy */
128
+ runOnDestroy = [];
124
129
  _id;
125
130
  get id() {
126
131
  return this._id;
@@ -134,7 +139,36 @@ export class Base {
134
139
  this._id = id;
135
140
  Base.idMap.set(id, this);
136
141
  }
142
+ /**
143
+ * Include next lines when extending this class:
144
+ * ```js
145
+ * static {
146
+ * this.registerSubclass()
147
+ * }
148
+ * ```
149
+ */
137
150
  static registerSubclass() {
138
151
  Base.subclasses.set(this.name, this);
139
152
  }
153
+ /**
154
+ * Destroy instance. Will run all `runOnDestroy` functions
155
+ * and remove istance from idMap.
156
+ * If class is garbage collected automatically runs this.
157
+ * */
158
+ destroy() {
159
+ Base.idMap.delete(this._id);
160
+ for (let index = 0; index < this.runOnDestroy.length; index++)
161
+ this.runOnDestroy[index]();
162
+ }
163
+ /**
164
+ * Register autocleared event handler.
165
+ * If using classes methods don't forget to `bind(this)`
166
+ */
167
+ registerEvent(target, type, listener, options = {}) {
168
+ options.passive ??= true;
169
+ target.addEventListener(type, listener, options);
170
+ this.runOnDestroy.push(() => {
171
+ target.removeEventListener(type, listener);
172
+ });
173
+ }
140
174
  }
package/dist/signals.d.ts CHANGED
@@ -31,7 +31,7 @@ export declare function signal<T>(value: T): Signal<T>;
31
31
  * Returned data from handler function will be passed to it on next signal change.
32
32
  * Returns a function that will clear the effect.
33
33
  *
34
- * ```ts
34
+ *
35
35
  * // Will print signal on change
36
36
  * effect(()=>{
37
37
  * console.log($mySignal())
@@ -42,7 +42,6 @@ export declare function signal<T>(value: T): Signal<T>;
42
42
  * if(last>mySignal) console.log('Increment!')
43
43
  * return mySignal;
44
44
  * })
45
- * ```
46
45
  */
47
46
  export declare function effect<T>(handler: (argument: T | undefined) => T, initialValue?: T): () => void;
48
47
  /**
package/dist/signals.js CHANGED
@@ -7,9 +7,9 @@ const effectsMap = new WeakMap();
7
7
  let batchedEffects;
8
8
  export function signal(value) {
9
9
  const subscribers = new Set();
10
- return (...arguments_) => {
11
- if (arguments_.length === 1) {
12
- const argument = arguments_[0];
10
+ return (...data) => {
11
+ if (data.length === 1) {
12
+ const argument = data[0];
13
13
  value =
14
14
  typeof argument === 'function'
15
15
  ? argument(value)
@@ -47,7 +47,7 @@ function clearEffect(handler) {
47
47
  * Returned data from handler function will be passed to it on next signal change.
48
48
  * Returns a function that will clear the effect.
49
49
  *
50
- * ```ts
50
+ *
51
51
  * // Will print signal on change
52
52
  * effect(()=>{
53
53
  * console.log($mySignal())
@@ -58,7 +58,6 @@ function clearEffect(handler) {
58
58
  * if(last>mySignal) console.log('Increment!')
59
59
  * return mySignal;
60
60
  * })
61
- * ```
62
61
  */
63
62
  export function effect(handler, initialValue) {
64
63
  let lastValue = initialValue;
package/dist/time.d.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  */
4
4
  import { AnyFunction } from './types';
5
5
  /** Measure performance of a function */
6
- export declare function measurePerformance(function_: () => unknown, timeCheck?: number): number;
6
+ export declare function measurePerformance(run: () => unknown, timeCheck?: number): number;
7
7
  /**
8
8
  * Original setTimeout and setIntval known for accumulating delay
9
9
  * and causing problem with timeouts bigger than 32bit integer.
@@ -21,7 +21,7 @@ export declare function setSafeInterval(handler: AnyFunction, delay: number): ()
21
21
  /** Like setInterval but with cron.
22
22
  * Returns clear function.
23
23
  * For cron string syntax check __getNextCron()__ description */
24
- export declare function cronInterval(function_: () => unknown, cronString: string): () => void;
24
+ export declare function cronInterval(run: () => unknown, cronString: string): () => void;
25
25
  /** Find next cron date after passed date.
26
26
  *
27
27
  * This function __DOES NOT__ implement regular CRON 1 to 1.
package/dist/time.js CHANGED
@@ -4,11 +4,11 @@
4
4
  import { HOUR_MS } from './consts';
5
5
  import { ValidationError } from './errors';
6
6
  /** Measure performance of a function */
7
- export function measurePerformance(function_, timeCheck = 16.6) {
7
+ export function measurePerformance(run, timeCheck = 16.6) {
8
8
  const endTime = performance.now() + timeCheck;
9
9
  let executions = 0;
10
10
  while (performance.now() < endTime) {
11
- function_();
11
+ run();
12
12
  executions++;
13
13
  }
14
14
  return executions;
@@ -61,7 +61,7 @@ export function setSafeInterval(handler, delay) {
61
61
  /** Like setInterval but with cron.
62
62
  * Returns clear function.
63
63
  * For cron string syntax check __getNextCron()__ description */
64
- export function cronInterval(function_, cronString) {
64
+ export function cronInterval(run, cronString) {
65
65
  let timeout;
66
66
  let next = getNextCron(cronString).getTime();
67
67
  const r = () => {
@@ -70,7 +70,7 @@ export function cronInterval(function_, cronString) {
70
70
  if (d < 1) {
71
71
  next = getNextCron(cronString).getTime();
72
72
  d = next - now;
73
- function_();
73
+ run();
74
74
  }
75
75
  timeout = setTimeout(r, Math.min(d, HOUR_MS));
76
76
  };
package/dist/types.d.ts CHANGED
@@ -4,7 +4,7 @@
4
4
  /** Values that are copied by value, not by reference */
5
5
  export type Primitive = string | number | bigint | boolean | symbol | null | undefined;
6
6
  /** Function with any arguments or return type */
7
- export type AnyFunction = (...arguments_: any[]) => any;
7
+ export type AnyFunction = (...data: any[]) => any;
8
8
  /** Values that convert to false */
9
9
  export type Falsy = false | '' | 0 | null | undefined;
10
10
  /** Make keys in object optional */
@@ -41,19 +41,16 @@ export type ObjectSnakeToCamel<T> = {
41
41
  export type Concat<T, U> = T extends any[] ? U extends any[] ? [...T, ...U] : never : T & U;
42
42
  /**
43
43
  * Visual only overhaul. Shows final type result on hover.
44
+ *
44
45
  * ```ts
45
46
  * type a = {a: '1'}
46
47
  * type b = Prettify<a & { b: 'b' }>
47
- * ```
48
- * On hovering b it will show
49
- * ```ts
48
+ * // On hovering b it will show
50
49
  * type b = {
51
50
  * a: "1";
52
51
  * b: "b";
53
52
  * }
54
- * ```
55
- * instead of
56
- * ```ts
53
+ * // instead of
57
54
  * type b = a & {
58
55
  * b: "b";
59
56
  * }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@softsky/utils",
3
- "version": "2.5.5",
3
+ "version": "2.6.0",
4
4
  "description": "JavaScript/TypeScript utilities",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -20,8 +20,8 @@
20
20
  },
21
21
  "homepage": "https://github.com/SoundOfTheSky/utils#readme",
22
22
  "devDependencies": {
23
- "@softsky/configs": "^1.3.3",
24
- "@types/bun": "^1.2.16"
23
+ "@softsky/configs": "^1.3.4",
24
+ "@types/bun": "^1.2.19"
25
25
  },
26
26
  "files": ["dist/**/*"]
27
27
  }