@naturalcycles/js-lib 14.73.0 → 14.76.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/dist/decorators/logMethod.decorator.js +1 -3
- package/dist/decorators/timeout.decorator.js +9 -1
- package/dist/error/try.d.ts +20 -0
- package/dist/error/try.js +47 -1
- package/dist/index.d.ts +20 -20
- package/dist/index.js +20 -52
- package/dist/math/math.util.d.ts +4 -0
- package/dist/math/math.util.js +18 -1
- package/dist/math/stack.util.d.ts +3 -2
- package/dist/math/stack.util.js +8 -5
- package/dist/promise/pTimeout.d.ts +10 -1
- package/dist/promise/pTimeout.js +43 -29
- package/dist/seq/seq.d.ts +30 -7
- package/dist/seq/seq.js +126 -9
- package/dist/string/stringifyAny.js +12 -10
- package/dist/unit/size.util.d.ts +6 -0
- package/dist/unit/size.util.js +33 -10
- package/dist-esm/decorators/logMethod.decorator.js +2 -4
- package/dist-esm/decorators/timeout.decorator.js +9 -1
- package/dist-esm/error/try.js +43 -0
- package/dist-esm/index.js +20 -20
- package/dist-esm/math/math.util.js +16 -0
- package/dist-esm/math/stack.util.js +9 -6
- package/dist-esm/promise/pTimeout.js +40 -28
- package/dist-esm/seq/seq.js +124 -8
- package/dist-esm/string/stringifyAny.js +12 -10
- package/dist-esm/unit/size.util.js +31 -9
- package/package.json +1 -1
- package/src/decorators/logMethod.decorator.ts +2 -4
- package/src/decorators/timeout.decorator.ts +12 -1
- package/src/error/try.ts +44 -0
- package/src/index.ts +20 -60
- package/src/math/math.util.ts +21 -0
- package/src/math/stack.util.ts +11 -7
- package/src/promise/pTimeout.ts +41 -29
- package/src/seq/seq.ts +144 -13
- package/src/string/stringifyAny.ts +13 -9
- package/src/unit/size.util.ts +22 -6
package/dist-esm/seq/seq.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { END, SKIP } from '../types';
|
|
1
|
+
import { END, SKIP, } from '../types';
|
|
2
2
|
/**
|
|
3
3
|
* Inspired by Kotlin Sequences.
|
|
4
4
|
* Similar to arrays, but with lazy evaluation, abortable.
|
|
@@ -7,7 +7,7 @@ import { END, SKIP } from '../types';
|
|
|
7
7
|
*
|
|
8
8
|
* @experimental
|
|
9
9
|
*/
|
|
10
|
-
export class
|
|
10
|
+
export class Sequence {
|
|
11
11
|
constructor(initialValue, nextFn) {
|
|
12
12
|
this.nextFn = nextFn;
|
|
13
13
|
this.sentInitialValue = false;
|
|
@@ -23,18 +23,18 @@ export class Seq {
|
|
|
23
23
|
};
|
|
24
24
|
}
|
|
25
25
|
static create(initialValue, nextFn) {
|
|
26
|
-
return new
|
|
26
|
+
return new Sequence(initialValue, nextFn);
|
|
27
27
|
}
|
|
28
28
|
static range(minIncl, maxExcl, step = 1) {
|
|
29
29
|
const max = maxExcl - step;
|
|
30
|
-
return new
|
|
30
|
+
return new Sequence(minIncl, n => (n < max ? n + step : END));
|
|
31
31
|
}
|
|
32
32
|
static from(a) {
|
|
33
33
|
const it = a[Symbol.iterator]();
|
|
34
34
|
const v = it.next();
|
|
35
35
|
if (v.done)
|
|
36
|
-
return new
|
|
37
|
-
return new
|
|
36
|
+
return new Sequence(END, () => { });
|
|
37
|
+
return new Sequence(v.value, () => {
|
|
38
38
|
const v = it.next();
|
|
39
39
|
if (v.done)
|
|
40
40
|
return END;
|
|
@@ -42,7 +42,7 @@ export class Seq {
|
|
|
42
42
|
});
|
|
43
43
|
}
|
|
44
44
|
static empty() {
|
|
45
|
-
return new
|
|
45
|
+
return new Sequence(END, () => { });
|
|
46
46
|
}
|
|
47
47
|
next() {
|
|
48
48
|
if (this.currentValue === END)
|
|
@@ -127,10 +127,126 @@ export class Seq {
|
|
|
127
127
|
a.push(v);
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
|
+
forEach(fn) {
|
|
131
|
+
let i = -1;
|
|
132
|
+
// eslint-disable-next-line no-constant-condition
|
|
133
|
+
while (true) {
|
|
134
|
+
const v = this.next();
|
|
135
|
+
if (v === END)
|
|
136
|
+
return;
|
|
137
|
+
fn(v, ++i);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
130
140
|
}
|
|
131
141
|
/**
|
|
132
142
|
* Convenience function to create a Sequence.
|
|
133
143
|
*/
|
|
134
144
|
export function _seq(initialValue, nextFn) {
|
|
135
|
-
return
|
|
145
|
+
return Sequence.create(initialValue, nextFn);
|
|
146
|
+
}
|
|
147
|
+
/* eslint-disable no-await-in-loop */
|
|
148
|
+
/**
|
|
149
|
+
* Experimental.
|
|
150
|
+
* Feasibility to be proven.
|
|
151
|
+
*
|
|
152
|
+
* @experimental
|
|
153
|
+
*/
|
|
154
|
+
export class AsyncSequence {
|
|
155
|
+
constructor(initialValue, nextFn) {
|
|
156
|
+
this.nextFn = nextFn;
|
|
157
|
+
this.sentInitialValue = false;
|
|
158
|
+
this.i = -1;
|
|
159
|
+
this.currentValue = initialValue;
|
|
160
|
+
}
|
|
161
|
+
[Symbol.asyncIterator]() {
|
|
162
|
+
return {
|
|
163
|
+
next: async () => {
|
|
164
|
+
const value = await this.next();
|
|
165
|
+
return value === END ? { done: true, value: undefined } : { value };
|
|
166
|
+
},
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
static create(initialValue, nextFn) {
|
|
170
|
+
return new AsyncSequence(initialValue, nextFn);
|
|
171
|
+
}
|
|
172
|
+
static async from(a) {
|
|
173
|
+
const it = a[Symbol.asyncIterator]();
|
|
174
|
+
const v = await it.next();
|
|
175
|
+
if (v.done)
|
|
176
|
+
return new AsyncSequence(END, () => { });
|
|
177
|
+
return new AsyncSequence(v.value, async () => {
|
|
178
|
+
const v = await it.next();
|
|
179
|
+
if (v.done)
|
|
180
|
+
return END;
|
|
181
|
+
return v.value;
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
static empty() {
|
|
185
|
+
return new AsyncSequence(END, () => { });
|
|
186
|
+
}
|
|
187
|
+
async next() {
|
|
188
|
+
if (this.currentValue === END)
|
|
189
|
+
return END;
|
|
190
|
+
this.i++;
|
|
191
|
+
let v;
|
|
192
|
+
if (!this.sentInitialValue) {
|
|
193
|
+
this.sentInitialValue = true;
|
|
194
|
+
v = this.currentValue;
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
v = await this.nextFn(this.currentValue, this.i);
|
|
198
|
+
}
|
|
199
|
+
// console.log(`_seq`, v)
|
|
200
|
+
if (v === SKIP)
|
|
201
|
+
return await this.next();
|
|
202
|
+
return (this.currentValue = v);
|
|
203
|
+
}
|
|
204
|
+
// Final functions - return final value, not a chained sequence
|
|
205
|
+
async find(predicate) {
|
|
206
|
+
do {
|
|
207
|
+
const v = await this.next();
|
|
208
|
+
if (v === END)
|
|
209
|
+
return; // not found, end of sequence
|
|
210
|
+
const r = await predicate(v, this.i);
|
|
211
|
+
if (r === END)
|
|
212
|
+
return;
|
|
213
|
+
if (r)
|
|
214
|
+
return v;
|
|
215
|
+
// otherwise proceed
|
|
216
|
+
} while (true); // eslint-disable-line no-constant-condition
|
|
217
|
+
}
|
|
218
|
+
async some(predicate) {
|
|
219
|
+
do {
|
|
220
|
+
const v = await this.next();
|
|
221
|
+
if (v === END)
|
|
222
|
+
return false;
|
|
223
|
+
const r = await predicate(v, this.i);
|
|
224
|
+
if (r === END)
|
|
225
|
+
return false;
|
|
226
|
+
if (r)
|
|
227
|
+
return true;
|
|
228
|
+
} while (true); // eslint-disable-line no-constant-condition
|
|
229
|
+
}
|
|
230
|
+
async every(predicate) {
|
|
231
|
+
do {
|
|
232
|
+
const v = await this.next();
|
|
233
|
+
if (v === END)
|
|
234
|
+
return true;
|
|
235
|
+
const r = await predicate(v, this.i);
|
|
236
|
+
if (r === END)
|
|
237
|
+
return true;
|
|
238
|
+
if (!r)
|
|
239
|
+
return false;
|
|
240
|
+
} while (true); // eslint-disable-line no-constant-condition
|
|
241
|
+
}
|
|
242
|
+
async toArray() {
|
|
243
|
+
const a = [];
|
|
244
|
+
// eslint-disable-next-line no-constant-condition
|
|
245
|
+
while (true) {
|
|
246
|
+
const v = await this.next();
|
|
247
|
+
if (v === END)
|
|
248
|
+
return a;
|
|
249
|
+
a.push(v);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
136
252
|
}
|
|
@@ -41,17 +41,19 @@ export function _stringifyAny(obj, opt = {}) {
|
|
|
41
41
|
//
|
|
42
42
|
// Error or ErrorObject
|
|
43
43
|
//
|
|
44
|
+
// Omit "default" error name as non-informative
|
|
45
|
+
// UPD: no, it's still important to understand that we're dealing with Error and not just some string
|
|
46
|
+
// if (obj?.name === 'Error') {
|
|
47
|
+
// s = obj.message
|
|
48
|
+
// }
|
|
49
|
+
s = [obj.name, obj.message].join(': ');
|
|
44
50
|
if (opt.includeErrorStack && obj.stack) {
|
|
45
|
-
//
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
//
|
|
50
|
-
|
|
51
|
-
// if (obj?.name === 'Error') {
|
|
52
|
-
// s = obj.message
|
|
53
|
-
// }
|
|
54
|
-
s = [obj.name, obj.message].join(': ');
|
|
51
|
+
// Here we're using the previously-generated "title line" (e.g "Error: some_message"),
|
|
52
|
+
// concatenating it with the Stack (but without the title line of the Stack)
|
|
53
|
+
// This is to fix the rare error (happened with Got) where `err.message` was changed,
|
|
54
|
+
// but err.stack had "old" err.message
|
|
55
|
+
// This should "fix" that
|
|
56
|
+
s = [s, ...obj.stack.split('\n').slice(1)].join('\n');
|
|
55
57
|
}
|
|
56
58
|
if (_isErrorObject(obj)) {
|
|
57
59
|
if (_isHttpErrorObject(obj)) {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export function _gb(b) {
|
|
2
|
-
return Math.round(b /
|
|
2
|
+
return Math.round(b / 1024 ** 3);
|
|
3
3
|
}
|
|
4
4
|
export function _mb(b) {
|
|
5
|
-
return Math.round(b /
|
|
5
|
+
return Math.round(b / 1024 ** 2);
|
|
6
6
|
}
|
|
7
7
|
export function _kb(b) {
|
|
8
8
|
return Math.round(b / 1024);
|
|
@@ -11,11 +11,33 @@ export function _kb(b) {
|
|
|
11
11
|
* Byte size to Human byte size string
|
|
12
12
|
*/
|
|
13
13
|
export function _hb(b = 0) {
|
|
14
|
-
if (b <
|
|
15
|
-
return `${Math.round(b)} byte
|
|
16
|
-
if (b <
|
|
17
|
-
return `${
|
|
18
|
-
if (b <
|
|
19
|
-
return `${
|
|
20
|
-
|
|
14
|
+
if (b < 1024)
|
|
15
|
+
return `${Math.round(b)} byte`;
|
|
16
|
+
if (b < 1024 ** 2)
|
|
17
|
+
return `${(b / 1024).toPrecision(3)} Kb`;
|
|
18
|
+
if (b < 1024 ** 3)
|
|
19
|
+
return `${(b / 1024 ** 2).toPrecision(3)} Mb`;
|
|
20
|
+
if (b < 1024 ** 4)
|
|
21
|
+
return `${(b / 1024 ** 3).toPrecision(3)} Gb`;
|
|
22
|
+
if (b < 1024 ** 5)
|
|
23
|
+
return `${(b / 1024 ** 4).toPrecision(3)} Tb`;
|
|
24
|
+
return `${Math.round(b / 1024 ** 4)} Tb`;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* hc stands for "human count", similar to "human bytes" `_hb` function.
|
|
28
|
+
* Helpful to print big numbers, as it adds `K` (kilo), `M` (mega), etc to make
|
|
29
|
+
* them more readable.
|
|
30
|
+
*/
|
|
31
|
+
export function _hc(c = 0) {
|
|
32
|
+
if (c < 10 ** 4)
|
|
33
|
+
return String(c);
|
|
34
|
+
if (c < 10 ** 6)
|
|
35
|
+
return (c / 10 ** 3).toPrecision(3) + ' K';
|
|
36
|
+
if (c < 10 ** 9)
|
|
37
|
+
return (c / 10 ** 6).toPrecision(3) + ' M'; // million
|
|
38
|
+
if (c < 10 ** 12)
|
|
39
|
+
return (c / 10 ** 9).toPrecision(3) + ' B'; // billion
|
|
40
|
+
if (c < 10 ** 15)
|
|
41
|
+
return (c / 10 ** 12).toPrecision(3) + ' T'; // trillion
|
|
42
|
+
return Math.round(c / 10 ** 12) + ' T';
|
|
21
43
|
}
|
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { SimpleMovingAverage, _stringifyAny, CommonLogger } from '..'
|
|
1
|
+
import { SimpleMovingAverage, _stringifyAny, CommonLogger, _assert } from '..'
|
|
2
2
|
import { _ms } from '../time/time.util'
|
|
3
3
|
import { _getArgsSignature, _getMethodSignature } from './decorator.util'
|
|
4
4
|
|
|
@@ -69,9 +69,7 @@ export interface LogMethodOptions {
|
|
|
69
69
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
70
70
|
export function _LogMethod(opt: LogMethodOptions = {}): MethodDecorator {
|
|
71
71
|
return (target, key, descriptor) => {
|
|
72
|
-
|
|
73
|
-
throw new TypeError('@_LogMethod can be applied only to methods')
|
|
74
|
-
}
|
|
72
|
+
_assert(typeof descriptor.value === 'function', '@_LogMethod can be applied only to methods')
|
|
75
73
|
|
|
76
74
|
const originalFn = descriptor.value
|
|
77
75
|
const keyStr = String(key)
|
|
@@ -1,10 +1,21 @@
|
|
|
1
|
+
import { _assert } from '../error/assert'
|
|
1
2
|
import { pTimeout, PTimeoutOptions } from '../promise/pTimeout'
|
|
3
|
+
import { _getMethodSignature } from './decorator.util'
|
|
2
4
|
|
|
3
5
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
4
6
|
export function _Timeout(opt: PTimeoutOptions): MethodDecorator {
|
|
5
7
|
return (target, key, descriptor) => {
|
|
8
|
+
_assert(typeof descriptor.value === 'function', '@_Timeout can be applied only to methods')
|
|
9
|
+
|
|
6
10
|
const originalFn = descriptor.value
|
|
7
|
-
|
|
11
|
+
const keyStr = String(key)
|
|
12
|
+
|
|
13
|
+
descriptor.value = async function (this: typeof target, ...args: any[]) {
|
|
14
|
+
const ctx = this
|
|
15
|
+
opt.name ||= _getMethodSignature(ctx, keyStr)
|
|
16
|
+
return await pTimeout(originalFn.apply(this, args), opt)
|
|
17
|
+
} as any
|
|
18
|
+
|
|
8
19
|
return descriptor
|
|
9
20
|
}
|
|
10
21
|
}
|
package/src/error/try.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { AnyFunction } from '../types'
|
|
2
|
+
import { AppError } from './app.error'
|
|
3
|
+
|
|
1
4
|
/**
|
|
2
5
|
* Calls a function, returns a Tuple of [error, value].
|
|
3
6
|
* Allows to write shorter code that avoids `try/catch`.
|
|
@@ -42,3 +45,44 @@ export async function pTry<ERR = unknown, RETURN = void>(
|
|
|
42
45
|
return [err as ERR, undefined as any]
|
|
43
46
|
}
|
|
44
47
|
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* It is thrown when Error was expected, but didn't happen
|
|
51
|
+
* ("pass" happened instead).
|
|
52
|
+
* "Pass" means "no error".
|
|
53
|
+
*/
|
|
54
|
+
export class UnexpectedPassError extends AppError {
|
|
55
|
+
constructor() {
|
|
56
|
+
super('_expectedError passed unexpectedly')
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Calls `fn`, expects is to throw, catches the expected error and returns.
|
|
62
|
+
* If error was NOT thrown - throws UnexpectedPassError instead.
|
|
63
|
+
*/
|
|
64
|
+
export function _expectedError<ERR = Error>(fn: AnyFunction): ERR {
|
|
65
|
+
try {
|
|
66
|
+
fn()
|
|
67
|
+
// Unexpected!
|
|
68
|
+
throw new UnexpectedPassError()
|
|
69
|
+
} catch (err) {
|
|
70
|
+
if (err instanceof UnexpectedPassError) throw err // re-throw
|
|
71
|
+
return err as ERR // this is expected!
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Awaits passed `promise`, expects is to throw (reject), catches the expected error and returns.
|
|
77
|
+
* If error was NOT thrown - throws UnexpectedPassError instead.
|
|
78
|
+
*/
|
|
79
|
+
export async function pExpectedError<ERR = Error>(promise: Promise<any>): Promise<ERR> {
|
|
80
|
+
try {
|
|
81
|
+
await promise
|
|
82
|
+
// Unexpected!
|
|
83
|
+
throw new UnexpectedPassError()
|
|
84
|
+
} catch (err) {
|
|
85
|
+
if (err instanceof UnexpectedPassError) throw err // re-throw
|
|
86
|
+
return err as ERR // this is expected!
|
|
87
|
+
}
|
|
88
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -7,26 +7,17 @@ import {
|
|
|
7
7
|
PromiseDecoratorResp,
|
|
8
8
|
_createPromiseDecorator,
|
|
9
9
|
} from './decorators/createPromiseDecorator'
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
export * from './decorators/debounce'
|
|
11
|
+
export * from './decorators/debounce.decorator'
|
|
12
|
+
export * from './decorators/decorator.util'
|
|
13
|
+
export * from './decorators/logMethod.decorator'
|
|
14
|
+
export * from './decorators/memo.decorator'
|
|
15
15
|
import { MemoCache } from './decorators/memo.util'
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
AssertionError,
|
|
22
|
-
_assert,
|
|
23
|
-
_assertDeepEquals,
|
|
24
|
-
_assertEquals,
|
|
25
|
-
_assertIsError,
|
|
26
|
-
_assertIsNumber,
|
|
27
|
-
_assertIsString,
|
|
28
|
-
_assertTypeOf,
|
|
29
|
-
} from './error/assert'
|
|
16
|
+
export * from './decorators/memoFn'
|
|
17
|
+
export * from './decorators/retry.decorator'
|
|
18
|
+
export * from './decorators/timeout.decorator'
|
|
19
|
+
export * from './error/app.error'
|
|
20
|
+
export * from './error/assert'
|
|
30
21
|
import {
|
|
31
22
|
Admin401ErrorData,
|
|
32
23
|
Admin403ErrorData,
|
|
@@ -37,11 +28,11 @@ import {
|
|
|
37
28
|
} from './error/error.model'
|
|
38
29
|
export * from './error/error.util'
|
|
39
30
|
import { ErrorMode } from './error/errorMode'
|
|
40
|
-
|
|
41
|
-
|
|
31
|
+
export * from './error/http.error'
|
|
32
|
+
export * from './error/try'
|
|
42
33
|
import { TryCatchOptions, _TryCatch, _tryCatch } from './error/tryCatch'
|
|
43
|
-
|
|
44
|
-
|
|
34
|
+
export * from './json-schema/from-data/generateJsonSchemaFromData'
|
|
35
|
+
export * from './json-schema/jsonSchema.cnst'
|
|
45
36
|
import {
|
|
46
37
|
JsonSchema,
|
|
47
38
|
JsonSchemaAllOf,
|
|
@@ -61,7 +52,7 @@ import {
|
|
|
61
52
|
JsonSchemaString,
|
|
62
53
|
JsonSchemaTuple,
|
|
63
54
|
} from './json-schema/jsonSchema.model'
|
|
64
|
-
|
|
55
|
+
export * from './json-schema/jsonSchema.util'
|
|
65
56
|
import {
|
|
66
57
|
jsonSchema,
|
|
67
58
|
JsonSchemaAnyBuilder,
|
|
@@ -85,13 +76,13 @@ import { pMap, PMapOptions } from './promise/pMap'
|
|
|
85
76
|
export * from './promise/pProps'
|
|
86
77
|
import { pRetry, PRetryOptions } from './promise/pRetry'
|
|
87
78
|
export * from './promise/pState'
|
|
88
|
-
import { pTimeout, PTimeoutOptions } from './promise/pTimeout'
|
|
79
|
+
import { pTimeout, pTimeoutFn, PTimeoutOptions } from './promise/pTimeout'
|
|
89
80
|
export * from './promise/pTuple'
|
|
90
81
|
export * from './string/case'
|
|
91
82
|
export * from './string/json.util'
|
|
92
83
|
export * from './string/string.util'
|
|
93
84
|
import { JsonStringifyFunction, StringifyAnyOptions, _stringifyAny } from './string/stringifyAny'
|
|
94
|
-
|
|
85
|
+
export * from './time/time.util'
|
|
95
86
|
import {
|
|
96
87
|
Class,
|
|
97
88
|
ConditionalExcept,
|
|
@@ -144,7 +135,7 @@ import {
|
|
|
144
135
|
_stringMapEntries,
|
|
145
136
|
_stringMapValues,
|
|
146
137
|
} from './types'
|
|
147
|
-
|
|
138
|
+
export * from './unit/size.util'
|
|
148
139
|
import { is } from './vendor/is'
|
|
149
140
|
import {
|
|
150
141
|
CommonLogLevel,
|
|
@@ -158,7 +149,7 @@ import {
|
|
|
158
149
|
CommonLogWithLevelFunction,
|
|
159
150
|
commonLoggerCreate,
|
|
160
151
|
} from './log/commonLogger'
|
|
161
|
-
|
|
152
|
+
export * from './string/safeJsonStringify'
|
|
162
153
|
import { PQueue, PQueueCfg } from './promise/pQueue'
|
|
163
154
|
export * from './seq/seq'
|
|
164
155
|
export * from './math/stack.util'
|
|
@@ -245,28 +236,10 @@ export type {
|
|
|
245
236
|
|
|
246
237
|
export {
|
|
247
238
|
is,
|
|
248
|
-
_Memo,
|
|
249
|
-
_memoFn,
|
|
250
|
-
_LogMethod,
|
|
251
|
-
_getArgsSignature,
|
|
252
239
|
_createPromiseDecorator,
|
|
253
|
-
AppError,
|
|
254
|
-
HttpError,
|
|
255
|
-
AssertionError,
|
|
256
|
-
_assert,
|
|
257
|
-
_assertEquals,
|
|
258
|
-
_assertDeepEquals,
|
|
259
|
-
_assertIsError,
|
|
260
|
-
_assertIsString,
|
|
261
|
-
_assertIsNumber,
|
|
262
|
-
_assertTypeOf,
|
|
263
240
|
_stringMapValues,
|
|
264
241
|
_stringMapEntries,
|
|
265
242
|
_objectKeys,
|
|
266
|
-
_debounce,
|
|
267
|
-
_throttle,
|
|
268
|
-
_Debounce,
|
|
269
|
-
_Throttle,
|
|
270
243
|
pMap,
|
|
271
244
|
_passthroughMapper,
|
|
272
245
|
_passUndefinedMapper,
|
|
@@ -278,31 +251,18 @@ export {
|
|
|
278
251
|
AggregatedError,
|
|
279
252
|
pRetry,
|
|
280
253
|
pTimeout,
|
|
281
|
-
|
|
282
|
-
_Timeout,
|
|
254
|
+
pTimeoutFn,
|
|
283
255
|
_tryCatch,
|
|
284
256
|
_TryCatch,
|
|
285
|
-
_try,
|
|
286
|
-
pTry,
|
|
287
257
|
_stringifyAny,
|
|
288
|
-
_ms,
|
|
289
|
-
_since,
|
|
290
|
-
_hb,
|
|
291
|
-
_gb,
|
|
292
|
-
_mb,
|
|
293
|
-
_kb,
|
|
294
|
-
mergeJsonSchemaObjects,
|
|
295
258
|
jsonSchema,
|
|
296
259
|
JsonSchemaAnyBuilder,
|
|
297
|
-
JSON_SCHEMA_ORDER,
|
|
298
|
-
generateJsonSchemaFromData,
|
|
299
260
|
commonLoggerMinLevel,
|
|
300
261
|
commonLoggerNoop,
|
|
301
262
|
commonLogLevelNumber,
|
|
302
263
|
commonLoggerPipe,
|
|
303
264
|
commonLoggerPrefix,
|
|
304
265
|
commonLoggerCreate,
|
|
305
|
-
_safeJsonStringify,
|
|
306
266
|
PQueue,
|
|
307
267
|
END,
|
|
308
268
|
SKIP,
|
package/src/math/math.util.ts
CHANGED
|
@@ -47,6 +47,27 @@ export function _percentile(values: number[], pc: number): number {
|
|
|
47
47
|
return _averageWeighted([sorted[floorPos]!, sorted[ceilPos]!], [1 - dec, dec])
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
/**
|
|
51
|
+
* A tiny bit more efficient function than calling _percentile individually.
|
|
52
|
+
*/
|
|
53
|
+
export function _percentiles(values: number[], pcs: number[]): Record<number, number> {
|
|
54
|
+
const r = {} as Record<number, number>
|
|
55
|
+
|
|
56
|
+
const sorted = _sortNumbers(values)
|
|
57
|
+
|
|
58
|
+
pcs.forEach(pc => {
|
|
59
|
+
// Floating pos in the range of [0; length - 1]
|
|
60
|
+
const pos = ((values.length - 1) * pc) / 100
|
|
61
|
+
const dec = pos % 1
|
|
62
|
+
const floorPos = Math.floor(pos)
|
|
63
|
+
const ceilPos = Math.ceil(pos)
|
|
64
|
+
|
|
65
|
+
r[pc] = _averageWeighted([sorted[floorPos]!, sorted[ceilPos]!], [1 - dec, dec])
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
return r
|
|
69
|
+
}
|
|
70
|
+
|
|
50
71
|
/**
|
|
51
72
|
* @example
|
|
52
73
|
*
|
package/src/math/stack.util.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { _average, _percentile, _range } from '../index'
|
|
1
|
+
import { _average, _percentile, _percentiles, _range } from '../index'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Implements a "round-robin" Stack ("first-in last-out" aka FILO) with a limited size.
|
|
@@ -64,6 +64,14 @@ export class NumberStack extends Stack<number> {
|
|
|
64
64
|
return this.items.length === 0 ? null : _average(this.items)
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
median(): number {
|
|
68
|
+
return _percentile(this.items, 50)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
medianOrNull(): number | null {
|
|
72
|
+
return this.items.length === 0 ? null : _percentile(this.items, 50)
|
|
73
|
+
}
|
|
74
|
+
|
|
67
75
|
/**
|
|
68
76
|
* `pc` is a number from 0 to 100 inclusive.
|
|
69
77
|
*/
|
|
@@ -80,11 +88,7 @@ export class NumberStack extends Stack<number> {
|
|
|
80
88
|
return this.items.length === 0 ? null : _percentile(this.items, pc)
|
|
81
89
|
}
|
|
82
90
|
|
|
83
|
-
|
|
84
|
-
return
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
medianOrNull(): number | null {
|
|
88
|
-
return this.items.length === 0 ? null : _percentile(this.items, 50)
|
|
91
|
+
percentiles(pcs: number[]): Record<number, number> {
|
|
92
|
+
return _percentiles(this.items, pcs)
|
|
89
93
|
}
|
|
90
94
|
}
|
package/src/promise/pTimeout.ts
CHANGED
|
@@ -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.
|
|
@@ -24,37 +27,46 @@ export interface PTimeoutOptions {
|
|
|
24
27
|
* Throws an Error if the Function is not resolved in a certain time.
|
|
25
28
|
* If the Function rejects - passes this rejection further.
|
|
26
29
|
*/
|
|
27
|
-
export function
|
|
28
|
-
|
|
30
|
+
export function pTimeoutFn<T extends AnyFunction>(fn: T, opt: PTimeoutOptions): T {
|
|
31
|
+
opt.name ||= fn.name
|
|
32
|
+
|
|
33
|
+
return async function pTimeoutInternalFn(this: any, ...args: any[]) {
|
|
34
|
+
return await pTimeout(fn.apply(this, args), opt)
|
|
35
|
+
} as any
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Decorates a Function with a timeout and immediately calls it.
|
|
40
|
+
* Throws an Error if the Function is not resolved in a certain time.
|
|
41
|
+
* If the Function rejects - passes this rejection further.
|
|
42
|
+
*/
|
|
43
|
+
export async function pTimeout<T>(promise: Promise<T>, opt: PTimeoutOptions): Promise<T> {
|
|
44
|
+
// todo: check how we can automatically infer function name (only applicable to named functions)
|
|
29
45
|
const { timeout, name, onTimeout } = opt
|
|
30
46
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
reject(err)
|
|
41
|
-
}
|
|
42
|
-
return
|
|
47
|
+
// eslint-disable-next-line no-async-promise-executor
|
|
48
|
+
return await new Promise(async (resolve, reject) => {
|
|
49
|
+
// Prepare the timeout timer
|
|
50
|
+
const timer = setTimeout(() => {
|
|
51
|
+
if (onTimeout) {
|
|
52
|
+
try {
|
|
53
|
+
resolve(onTimeout())
|
|
54
|
+
} catch (err) {
|
|
55
|
+
reject(err)
|
|
43
56
|
}
|
|
44
|
-
|
|
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
|
+
return
|
|
57
58
|
}
|
|
58
|
-
|
|
59
|
-
|
|
59
|
+
|
|
60
|
+
reject(new TimeoutError(`"${name || 'pTimeout function'}" timed out after ${timeout} ms`))
|
|
61
|
+
}, timeout)
|
|
62
|
+
|
|
63
|
+
// Execute the Function
|
|
64
|
+
try {
|
|
65
|
+
resolve(await promise)
|
|
66
|
+
} catch (err) {
|
|
67
|
+
reject(err)
|
|
68
|
+
} finally {
|
|
69
|
+
clearTimeout(timer)
|
|
70
|
+
}
|
|
71
|
+
})
|
|
60
72
|
}
|