@naturalcycles/js-lib 14.81.0 → 14.84.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/asyncMemo.decorator.d.ts +22 -0
- package/dist/decorators/asyncMemo.decorator.js +96 -0
- package/dist/decorators/memo.decorator.d.ts +8 -0
- package/dist/decorators/memo.decorator.js +11 -6
- package/dist/decorators/memo.util.d.ts +27 -8
- package/dist/decorators/memo.util.js +1 -1
- package/dist/error/error.model.d.ts +6 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +1 -1
- package/dist/promise/AggregatedError.d.ts +1 -1
- package/dist/promise/AggregatedError.js +2 -7
- package/dist/promise/pFilter.d.ts +2 -3
- package/dist/promise/pFilter.js +4 -4
- package/dist/promise/pMap.d.ts +1 -1
- package/dist/promise/pMap.js +67 -19
- package/dist/promise/pRetry.d.ts +6 -2
- package/dist/promise/pRetry.js +6 -1
- package/dist/promise/pTimeout.d.ts +5 -1
- package/dist/promise/pTimeout.js +5 -1
- package/dist-esm/decorators/asyncMemo.decorator.js +104 -0
- package/dist-esm/decorators/memo.decorator.js +11 -5
- package/dist-esm/decorators/memo.util.js +1 -1
- package/dist-esm/index.js +1 -1
- package/dist-esm/promise/AggregatedError.js +2 -7
- package/dist-esm/promise/pFilter.js +4 -4
- package/dist-esm/promise/pMap.js +79 -19
- package/dist-esm/promise/pRetry.js +3 -1
- package/dist-esm/promise/pTimeout.js +2 -1
- package/package.json +1 -1
- package/src/decorators/asyncMemo.decorator.ts +151 -0
- package/src/decorators/memo.decorator.ts +16 -5
- package/src/decorators/memo.util.ts +36 -10
- package/src/error/error.model.ts +7 -0
- package/src/index.ts +3 -2
- package/src/promise/AggregatedError.ts +3 -8
- package/src/promise/pFilter.ts +5 -14
- package/src/promise/pMap.ts +72 -21
- package/src/promise/pRetry.ts +13 -3
- package/src/promise/pTimeout.ts +14 -2
- package/dist/promise/pBatch.d.ts +0 -7
- package/dist/promise/pBatch.js +0 -30
- package/dist-esm/promise/pBatch.js +0 -23
- package/src/promise/pBatch.ts +0 -31
package/src/index.ts
CHANGED
|
@@ -12,7 +12,8 @@ export * from './decorators/debounce.decorator'
|
|
|
12
12
|
export * from './decorators/decorator.util'
|
|
13
13
|
export * from './decorators/logMethod.decorator'
|
|
14
14
|
export * from './decorators/memo.decorator'
|
|
15
|
-
|
|
15
|
+
export * from './decorators/asyncMemo.decorator'
|
|
16
|
+
import { MemoCache, AsyncMemoCache } from './decorators/memo.util'
|
|
16
17
|
export * from './decorators/memoFn'
|
|
17
18
|
export * from './decorators/retry.decorator'
|
|
18
19
|
export * from './decorators/timeout.decorator'
|
|
@@ -67,7 +68,6 @@ export * from './object/object.util'
|
|
|
67
68
|
export * from './object/sortObject'
|
|
68
69
|
export * from './object/sortObjectDeep'
|
|
69
70
|
import { AggregatedError } from './promise/AggregatedError'
|
|
70
|
-
export * from './promise/pBatch'
|
|
71
71
|
import { DeferredPromise, pDefer } from './promise/pDefer'
|
|
72
72
|
export * from './promise/pDelay'
|
|
73
73
|
export * from './promise/pFilter'
|
|
@@ -161,6 +161,7 @@ export type {
|
|
|
161
161
|
AbortableAsyncMapper,
|
|
162
162
|
PQueueCfg,
|
|
163
163
|
MemoCache,
|
|
164
|
+
AsyncMemoCache,
|
|
164
165
|
PromiseDecoratorCfg,
|
|
165
166
|
PromiseDecoratorResp,
|
|
166
167
|
ErrorData,
|
|
@@ -7,20 +7,15 @@ export class AggregatedError<RESULT = any> extends Error {
|
|
|
7
7
|
errors!: Error[]
|
|
8
8
|
results!: RESULT[]
|
|
9
9
|
|
|
10
|
-
constructor(errors:
|
|
11
|
-
const mappedErrors = errors.map(e => {
|
|
12
|
-
if (typeof e === 'string') return new Error(e)
|
|
13
|
-
return e
|
|
14
|
-
})
|
|
15
|
-
|
|
10
|
+
constructor(errors: Error[], results: RESULT[] = []) {
|
|
16
11
|
const message = [
|
|
17
12
|
`${errors.length} errors:`,
|
|
18
|
-
...
|
|
13
|
+
...errors.map((e, i) => `${i + 1}. ${e.message}`),
|
|
19
14
|
].join('\n')
|
|
20
15
|
|
|
21
16
|
super(message)
|
|
22
17
|
|
|
23
|
-
this.errors =
|
|
18
|
+
this.errors = errors
|
|
24
19
|
this.results = results
|
|
25
20
|
|
|
26
21
|
Object.defineProperty(this, 'name', {
|
package/src/promise/pFilter.ts
CHANGED
|
@@ -1,16 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { pMap, PMapOptions } from './pMap'
|
|
1
|
+
import { AsyncPredicate } from '../types'
|
|
3
2
|
|
|
4
|
-
export async function pFilter<T>(
|
|
5
|
-
|
|
6
|
-
filterFn
|
|
7
|
-
|
|
8
|
-
): Promise<T[]> {
|
|
9
|
-
const values = await pMap(
|
|
10
|
-
iterable,
|
|
11
|
-
async (item, index) => await Promise.all([filterFn(item, index), item]),
|
|
12
|
-
opt,
|
|
13
|
-
)
|
|
14
|
-
|
|
15
|
-
return values.filter(value => Boolean(value[0])).map(value => value[1])
|
|
3
|
+
export async function pFilter<T>(iterable: Iterable<T>, filterFn: AsyncPredicate<T>): Promise<T[]> {
|
|
4
|
+
const items = [...iterable]
|
|
5
|
+
const predicates = await Promise.all(items.map((item, i) => filterFn(item, i)))
|
|
6
|
+
return items.filter((item, i) => predicates[i])
|
|
16
7
|
}
|
package/src/promise/pMap.ts
CHANGED
|
@@ -55,36 +55,85 @@ export interface PMapOptions {
|
|
|
55
55
|
* })();
|
|
56
56
|
*/
|
|
57
57
|
export async function pMap<IN, OUT>(
|
|
58
|
-
iterable: Iterable<IN
|
|
58
|
+
iterable: Iterable<IN>,
|
|
59
59
|
mapper: AbortableAsyncMapper<IN, OUT>,
|
|
60
60
|
opt: PMapOptions = {},
|
|
61
61
|
): Promise<OUT[]> {
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
const ret: (OUT | typeof SKIP)[] = []
|
|
63
|
+
// const iterator = iterable[Symbol.iterator]()
|
|
64
|
+
const items = [...iterable]
|
|
65
|
+
const itemsLength = items.length
|
|
66
|
+
if (itemsLength === 0) return [] // short circuit
|
|
67
|
+
|
|
68
|
+
const { concurrency = itemsLength, errorMode = ErrorMode.THROW_IMMEDIATELY } = opt
|
|
69
|
+
|
|
70
|
+
const errors: Error[] = []
|
|
71
|
+
let isSettled = false
|
|
72
|
+
let resolvingCount = 0
|
|
73
|
+
let currentIndex = 0
|
|
74
|
+
|
|
75
|
+
// Special cases that are able to preserve async stack traces
|
|
76
|
+
|
|
77
|
+
if (concurrency === 1) {
|
|
78
|
+
// Special case for concurrency == 1
|
|
79
|
+
|
|
80
|
+
for await (const item of items) {
|
|
81
|
+
try {
|
|
82
|
+
const r = await mapper(item, currentIndex++)
|
|
83
|
+
if (r === END) break
|
|
84
|
+
if (r !== SKIP) ret.push(r)
|
|
85
|
+
} catch (err) {
|
|
86
|
+
if (errorMode === ErrorMode.THROW_IMMEDIATELY) throw err
|
|
87
|
+
if (errorMode === ErrorMode.THROW_AGGREGATED) {
|
|
88
|
+
errors.push(err as Error)
|
|
89
|
+
}
|
|
90
|
+
// otherwise, suppress completely
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (errors.length) {
|
|
95
|
+
throw new AggregatedError(errors, ret)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return ret as OUT[]
|
|
99
|
+
} else if (!opt.concurrency || items.length <= opt.concurrency) {
|
|
100
|
+
// Special case for concurrency == infinity or iterable.length < concurrency
|
|
101
|
+
|
|
102
|
+
if (errorMode === ErrorMode.THROW_IMMEDIATELY) {
|
|
103
|
+
return (await Promise.all(items.map((item, i) => mapper(item, i)))).filter(
|
|
104
|
+
r => r !== SKIP && r !== END,
|
|
105
|
+
) as OUT[]
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
;(await Promise.allSettled(items.map((item, i) => mapper(item, i)))).forEach(r => {
|
|
109
|
+
if (r.status === 'fulfilled') {
|
|
110
|
+
if (r.value !== SKIP && r.value !== END) ret.push(r.value)
|
|
111
|
+
} else if (errorMode === ErrorMode.THROW_AGGREGATED) {
|
|
112
|
+
errors.push(r.reason)
|
|
113
|
+
}
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
if (errors.length) {
|
|
117
|
+
throw new AggregatedError(errors, ret)
|
|
118
|
+
}
|
|
64
119
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
const errors: Error[] = []
|
|
68
|
-
let isSettled = false
|
|
69
|
-
let isIterableDone = false
|
|
70
|
-
let resolvingCount = 0
|
|
71
|
-
let currentIndex = 0
|
|
120
|
+
return ret as OUT[]
|
|
121
|
+
}
|
|
72
122
|
|
|
73
|
-
|
|
123
|
+
return new Promise<OUT[]>((resolve, reject) => {
|
|
124
|
+
const next = () => {
|
|
74
125
|
if (isSettled) {
|
|
75
126
|
return
|
|
76
127
|
}
|
|
77
128
|
|
|
78
|
-
const nextItem =
|
|
79
|
-
const i = currentIndex
|
|
80
|
-
if (!skipped) currentIndex++
|
|
81
|
-
|
|
82
|
-
if (nextItem.done) {
|
|
83
|
-
isIterableDone = true
|
|
129
|
+
const nextItem = items[currentIndex]!
|
|
130
|
+
const i = currentIndex++
|
|
84
131
|
|
|
132
|
+
if (currentIndex > itemsLength) {
|
|
85
133
|
if (resolvingCount === 0) {
|
|
134
|
+
isSettled = true
|
|
86
135
|
const r = ret.filter(r => r !== SKIP) as OUT[]
|
|
87
|
-
if (errors.length
|
|
136
|
+
if (errors.length) {
|
|
88
137
|
reject(new AggregatedError(errors, r))
|
|
89
138
|
} else {
|
|
90
139
|
resolve(r)
|
|
@@ -96,7 +145,7 @@ export async function pMap<IN, OUT>(
|
|
|
96
145
|
|
|
97
146
|
resolvingCount++
|
|
98
147
|
|
|
99
|
-
Promise.resolve(nextItem
|
|
148
|
+
Promise.resolve(nextItem)
|
|
100
149
|
.then(async element => await mapper(element, i))
|
|
101
150
|
.then(
|
|
102
151
|
value => {
|
|
@@ -114,7 +163,9 @@ export async function pMap<IN, OUT>(
|
|
|
114
163
|
isSettled = true
|
|
115
164
|
reject(err)
|
|
116
165
|
} else {
|
|
117
|
-
|
|
166
|
+
if (errorMode === ErrorMode.THROW_AGGREGATED) {
|
|
167
|
+
errors.push(err)
|
|
168
|
+
}
|
|
118
169
|
resolvingCount--
|
|
119
170
|
next()
|
|
120
171
|
}
|
|
@@ -125,7 +176,7 @@ export async function pMap<IN, OUT>(
|
|
|
125
176
|
for (let i = 0; i < concurrency; i++) {
|
|
126
177
|
next()
|
|
127
178
|
|
|
128
|
-
if (
|
|
179
|
+
if (isSettled) {
|
|
129
180
|
break
|
|
130
181
|
}
|
|
131
182
|
}
|
package/src/promise/pRetry.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { _since, _stringifyAny, AnyFunction, CommonLogger } from '..'
|
|
1
|
+
import { _since, _stringifyAny, AnyFunction, AnyObject, AppError, CommonLogger } from '..'
|
|
2
2
|
import { TimeoutError } from './pTimeout'
|
|
3
3
|
|
|
4
4
|
export interface PRetryOptions {
|
|
@@ -11,7 +11,7 @@ export interface PRetryOptions {
|
|
|
11
11
|
/**
|
|
12
12
|
* Timeout for each Try, in milliseconds.
|
|
13
13
|
*
|
|
14
|
-
* Defaults to
|
|
14
|
+
* Defaults to no timeout.
|
|
15
15
|
*/
|
|
16
16
|
timeout?: number
|
|
17
17
|
|
|
@@ -91,6 +91,11 @@ export interface PRetryOptions {
|
|
|
91
91
|
* @experimental
|
|
92
92
|
*/
|
|
93
93
|
keepStackTrace?: boolean
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Will be merged with `err.data` object.
|
|
97
|
+
*/
|
|
98
|
+
errorData?: AnyObject
|
|
94
99
|
}
|
|
95
100
|
|
|
96
101
|
/**
|
|
@@ -139,7 +144,7 @@ export async function pRetry<T>(
|
|
|
139
144
|
return await new Promise((resolve, reject) => {
|
|
140
145
|
const rejectWithTimeout = () => {
|
|
141
146
|
timedOut = true // to prevent more tries
|
|
142
|
-
const err = new TimeoutError(`"${fname}" timed out after ${timeout} ms
|
|
147
|
+
const err = new TimeoutError(`"${fname}" timed out after ${timeout} ms`, opt.errorData)
|
|
143
148
|
if (fakeError) {
|
|
144
149
|
// keep original stack
|
|
145
150
|
err.stack = fakeError.stack!.replace('Error: RetryError', 'TimeoutError')
|
|
@@ -199,6 +204,11 @@ export async function pRetry<T>(
|
|
|
199
204
|
})
|
|
200
205
|
}
|
|
201
206
|
|
|
207
|
+
;(err as AppError).data = {
|
|
208
|
+
...(err as AppError).data,
|
|
209
|
+
...opt.errorData,
|
|
210
|
+
}
|
|
211
|
+
|
|
202
212
|
reject(err)
|
|
203
213
|
} else {
|
|
204
214
|
// Retry after delay
|
package/src/promise/pTimeout.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AppError } from '../error/app.error'
|
|
2
|
-
import { AnyFunction } from '../types'
|
|
2
|
+
import { AnyFunction, AnyObject } from '../types'
|
|
3
3
|
|
|
4
4
|
export class TimeoutError extends AppError {}
|
|
5
5
|
|
|
@@ -29,6 +29,11 @@ export interface PTimeoutOptions {
|
|
|
29
29
|
* @experimental
|
|
30
30
|
*/
|
|
31
31
|
keepStackTrace?: boolean
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Will be merged with `err.data` object.
|
|
35
|
+
*/
|
|
36
|
+
errorData?: AnyObject
|
|
32
37
|
}
|
|
33
38
|
|
|
34
39
|
/**
|
|
@@ -63,12 +68,19 @@ export async function pTimeout<T>(promise: Promise<T>, opt: PTimeoutOptions): Pr
|
|
|
63
68
|
resolve(onTimeout())
|
|
64
69
|
} catch (err: any) {
|
|
65
70
|
if (fakeError) err.stack = fakeError.stack // keep original stack
|
|
71
|
+
err.data = {
|
|
72
|
+
...err.data,
|
|
73
|
+
...opt.errorData,
|
|
74
|
+
}
|
|
66
75
|
reject(err)
|
|
67
76
|
}
|
|
68
77
|
return
|
|
69
78
|
}
|
|
70
79
|
|
|
71
|
-
const err = new TimeoutError(
|
|
80
|
+
const err = new TimeoutError(
|
|
81
|
+
`"${name || 'pTimeout function'}" timed out after ${timeout} ms`,
|
|
82
|
+
opt.errorData,
|
|
83
|
+
)
|
|
72
84
|
if (fakeError) err.stack = fakeError.stack // keep original stack
|
|
73
85
|
reject(err)
|
|
74
86
|
}, timeout)
|
package/dist/promise/pBatch.d.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { AbortableAsyncMapper, BatchResult } from '..';
|
|
2
|
-
/**
|
|
3
|
-
* Like pMap, but doesn't fail on errors, instead returns both successful results and errors.
|
|
4
|
-
*/
|
|
5
|
-
export declare function pBatch<IN, OUT>(iterable: Iterable<IN | PromiseLike<IN>>, mapper: AbortableAsyncMapper<IN, OUT>, opt?: {
|
|
6
|
-
concurrency?: number;
|
|
7
|
-
}): Promise<BatchResult<OUT>>;
|
package/dist/promise/pBatch.js
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.pBatch = void 0;
|
|
4
|
-
const __1 = require("..");
|
|
5
|
-
const pMap_1 = require("./pMap");
|
|
6
|
-
/**
|
|
7
|
-
* Like pMap, but doesn't fail on errors, instead returns both successful results and errors.
|
|
8
|
-
*/
|
|
9
|
-
async function pBatch(iterable, mapper, opt) {
|
|
10
|
-
try {
|
|
11
|
-
const results = await (0, pMap_1.pMap)(iterable, mapper, {
|
|
12
|
-
...opt,
|
|
13
|
-
errorMode: __1.ErrorMode.THROW_AGGREGATED,
|
|
14
|
-
});
|
|
15
|
-
return {
|
|
16
|
-
results,
|
|
17
|
-
errors: [],
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
catch (err) {
|
|
21
|
-
const { errors, results } = err;
|
|
22
|
-
if (!errors || !results)
|
|
23
|
-
throw err; // not an AggregatedError
|
|
24
|
-
return {
|
|
25
|
-
results,
|
|
26
|
-
errors,
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
exports.pBatch = pBatch;
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { ErrorMode } from '..';
|
|
2
|
-
import { pMap } from './pMap';
|
|
3
|
-
/**
|
|
4
|
-
* Like pMap, but doesn't fail on errors, instead returns both successful results and errors.
|
|
5
|
-
*/
|
|
6
|
-
export async function pBatch(iterable, mapper, opt) {
|
|
7
|
-
try {
|
|
8
|
-
const results = await pMap(iterable, mapper, Object.assign(Object.assign({}, opt), { errorMode: ErrorMode.THROW_AGGREGATED }));
|
|
9
|
-
return {
|
|
10
|
-
results,
|
|
11
|
-
errors: [],
|
|
12
|
-
};
|
|
13
|
-
}
|
|
14
|
-
catch (err) {
|
|
15
|
-
const { errors, results } = err;
|
|
16
|
-
if (!errors || !results)
|
|
17
|
-
throw err; // not an AggregatedError
|
|
18
|
-
return {
|
|
19
|
-
results,
|
|
20
|
-
errors,
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
}
|
package/src/promise/pBatch.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { AbortableAsyncMapper, BatchResult, ErrorMode } from '..'
|
|
2
|
-
import { AggregatedError } from './AggregatedError'
|
|
3
|
-
import { pMap } from './pMap'
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Like pMap, but doesn't fail on errors, instead returns both successful results and errors.
|
|
7
|
-
*/
|
|
8
|
-
export async function pBatch<IN, OUT>(
|
|
9
|
-
iterable: Iterable<IN | PromiseLike<IN>>,
|
|
10
|
-
mapper: AbortableAsyncMapper<IN, OUT>,
|
|
11
|
-
opt?: { concurrency?: number },
|
|
12
|
-
): Promise<BatchResult<OUT>> {
|
|
13
|
-
try {
|
|
14
|
-
const results = await pMap(iterable, mapper, {
|
|
15
|
-
...opt,
|
|
16
|
-
errorMode: ErrorMode.THROW_AGGREGATED,
|
|
17
|
-
})
|
|
18
|
-
return {
|
|
19
|
-
results,
|
|
20
|
-
errors: [],
|
|
21
|
-
}
|
|
22
|
-
} catch (err) {
|
|
23
|
-
const { errors, results } = err as AggregatedError<OUT>
|
|
24
|
-
if (!errors || !results) throw err // not an AggregatedError
|
|
25
|
-
|
|
26
|
-
return {
|
|
27
|
-
results,
|
|
28
|
-
errors,
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|