@naturalcycles/js-lib 14.75.1 → 14.78.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,8 @@
1
+ import { AppError } from '../error/app.error'
1
2
  import { AnyFunction } from '../types'
2
3
 
4
+ export class TimeoutError extends AppError {}
5
+
3
6
  export interface PTimeoutOptions {
4
7
  /**
5
8
  * Timeout in milliseconds.
@@ -17,6 +20,15 @@ export interface PTimeoutOptions {
17
20
  * Can be used to thrown a custom error OR resolve a promise without throwing.
18
21
  */
19
22
  onTimeout?: () => any
23
+
24
+ /**
25
+ * Defaults to true.
26
+ * If true - preserves the stack trace in case of a Timeout (usually - very useful!).
27
+ * It has a certain perf cost.
28
+ *
29
+ * @experimental
30
+ */
31
+ keepStackTrace?: boolean
20
32
  }
21
33
 
22
34
  /**
@@ -24,37 +36,50 @@ export interface PTimeoutOptions {
24
36
  * Throws an Error if the Function is not resolved in a certain time.
25
37
  * If the Function rejects - passes this rejection further.
26
38
  */
27
- export function pTimeout<T extends AnyFunction>(fn: T, opt: PTimeoutOptions): T {
28
- // const fname = fn.name || 'function'
29
- const { timeout, name, onTimeout } = opt
30
-
31
- return async function (this: any, ...args: any[]) {
32
- // eslint-disable-next-line no-async-promise-executor
33
- return await new Promise(async (resolve, reject) => {
34
- // Prepare the timeout timer
35
- const timer = setTimeout(() => {
36
- if (onTimeout) {
37
- try {
38
- resolve(onTimeout())
39
- } catch (err) {
40
- reject(err)
41
- }
42
- return
43
- }
39
+ export function pTimeoutFn<T extends AnyFunction>(fn: T, opt: PTimeoutOptions): T {
40
+ opt.name ||= fn.name
44
41
 
45
- reject(
46
- new Error(`"${name || fn.name || 'pTimeout function'}" timed out after ${timeout} ms`),
47
- )
48
- }, timeout)
49
-
50
- // Execute the Function
51
- try {
52
- resolve(await fn.apply(this, args))
53
- } catch (err) {
54
- reject(err)
55
- } finally {
56
- clearTimeout(timer)
57
- }
58
- })
42
+ return async function pTimeoutInternalFn(this: any, ...args: any[]) {
43
+ return await pTimeout(fn.apply(this, args), opt)
59
44
  } as any
60
45
  }
46
+
47
+ /**
48
+ * Decorates a Function with a timeout and immediately calls it.
49
+ * Throws an Error if the Function is not resolved in a certain time.
50
+ * If the Function rejects - passes this rejection further.
51
+ */
52
+ export async function pTimeout<T>(promise: Promise<T>, opt: PTimeoutOptions): Promise<T> {
53
+ // todo: check how we can automatically infer function name (only applicable to named functions)
54
+ const { timeout, name, onTimeout, keepStackTrace = true } = opt
55
+ const fakeError = keepStackTrace ? new Error('TimeoutError') : undefined
56
+
57
+ // eslint-disable-next-line no-async-promise-executor
58
+ return await new Promise(async (resolve, reject) => {
59
+ // Prepare the timeout timer
60
+ const timer = setTimeout(() => {
61
+ if (onTimeout) {
62
+ try {
63
+ resolve(onTimeout())
64
+ } catch (err: any) {
65
+ if (fakeError) err.stack = fakeError.stack // keep original stack
66
+ reject(err)
67
+ }
68
+ return
69
+ }
70
+
71
+ const err = new TimeoutError(`"${name || 'pTimeout function'}" timed out after ${timeout} ms`)
72
+ if (fakeError) err.stack = fakeError.stack // keep original stack
73
+ reject(err)
74
+ }, timeout)
75
+
76
+ // Execute the Function
77
+ try {
78
+ resolve(await promise)
79
+ } catch (err) {
80
+ reject(err)
81
+ } finally {
82
+ clearTimeout(timer)
83
+ }
84
+ })
85
+ }
package/src/seq/seq.ts CHANGED
@@ -140,6 +140,16 @@ export class Sequence<T> implements Iterable<T> {
140
140
  a.push(v)
141
141
  }
142
142
  }
143
+
144
+ forEach(fn: (v: T, i: number) => void): void {
145
+ let i = -1
146
+ // eslint-disable-next-line no-constant-condition
147
+ while (true) {
148
+ const v = this.next()
149
+ if (v === END) return
150
+ fn(v, ++i)
151
+ }
152
+ }
143
153
  }
144
154
 
145
155
  /**
package/src/types.ts CHANGED
@@ -122,9 +122,18 @@ export type ValueOf<T> = T[keyof T]
122
122
 
123
123
  export type KeyValueTuple<K, V> = [key: K, value: V]
124
124
 
125
- export type ObjectMapper<OBJ, OUT> = (key: string, value: OBJ[keyof OBJ], obj: OBJ) => OUT
126
-
127
- export type ObjectPredicate<OBJ> = (key: keyof OBJ, value: OBJ[keyof OBJ], obj: OBJ) => boolean
125
+ // Exclude<something, undefined> is used here to support StringMap<OBJ> (because values of StringMap add `undefined`)
126
+ export type ObjectMapper<OBJ, OUT> = (
127
+ key: string,
128
+ value: Exclude<OBJ[keyof OBJ], undefined>,
129
+ obj: OBJ,
130
+ ) => OUT
131
+
132
+ export type ObjectPredicate<OBJ> = (
133
+ key: keyof OBJ,
134
+ value: Exclude<OBJ[keyof OBJ], undefined>,
135
+ obj: OBJ,
136
+ ) => boolean
128
137
 
129
138
  /**
130
139
  * Allows to identify instance of Class by `instanceId`.
@@ -1,9 +1,9 @@
1
1
  export function _gb(b: number): number {
2
- return Math.round(b / (1024 * 1024 * 1024))
2
+ return Math.round(b / 1024 ** 3)
3
3
  }
4
4
 
5
5
  export function _mb(b: number): number {
6
- return Math.round(b / (1024 * 1024))
6
+ return Math.round(b / 1024 ** 2)
7
7
  }
8
8
 
9
9
  export function _kb(b: number): number {
@@ -14,8 +14,24 @@ export function _kb(b: number): number {
14
14
  * Byte size to Human byte size string
15
15
  */
16
16
  export function _hb(b = 0): string {
17
- if (b < 800) return `${Math.round(b)} byte(s)`
18
- if (b < 800 * 1024) return `${Math.round(b / 1024)} Kb`
19
- if (b < 800 * 1024 * 1024) return `${Math.round(b / 1024 / 1024)} Mb`
20
- return `${Math.round(b / 1024 / 1024 / 1024)} Gb`
17
+ if (b < 1024) return `${Math.round(b)} byte`
18
+ if (b < 1024 ** 2) return `${(b / 1024).toPrecision(3)} Kb`
19
+ if (b < 1024 ** 3) return `${(b / 1024 ** 2).toPrecision(3)} Mb`
20
+ if (b < 1024 ** 4) return `${(b / 1024 ** 3).toPrecision(3)} Gb`
21
+ if (b < 1024 ** 5) return `${(b / 1024 ** 4).toPrecision(3)} Tb`
22
+ return `${Math.round(b / 1024 ** 4)} Tb`
23
+ }
24
+
25
+ /**
26
+ * hc stands for "human count", similar to "human bytes" `_hb` function.
27
+ * Helpful to print big numbers, as it adds `K` (kilo), `M` (mega), etc to make
28
+ * them more readable.
29
+ */
30
+ export function _hc(c = 0): string {
31
+ if (c < 10 ** 4) return String(c)
32
+ if (c < 10 ** 6) return (c / 10 ** 3).toPrecision(3) + ' K'
33
+ if (c < 10 ** 9) return (c / 10 ** 6).toPrecision(3) + ' M' // million
34
+ if (c < 10 ** 12) return (c / 10 ** 9).toPrecision(3) + ' B' // billion
35
+ if (c < 10 ** 15) return (c / 10 ** 12).toPrecision(3) + ' T' // trillion
36
+ return Math.round(c / 10 ** 12) + ' T'
21
37
  }