@naturalcycles/js-lib 14.218.0 → 14.219.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.
@@ -4,7 +4,11 @@ export interface PMapOptions {
4
4
  /**
5
5
  * Number of concurrently pending promises returned by `mapper`.
6
6
  *
7
- * @default Infinity
7
+ * Defaults to 16.
8
+ *
9
+ * It previously (and originally) defaulted to Infinity, which was later changed,
10
+ * because it's somewhat dangerous to run "infinite number of parallel promises".
11
+ * You can still emulate the old behavior by passing `Infinity`.
8
12
  */
9
13
  concurrency?: number;
10
14
  /**
@@ -23,6 +27,14 @@ export interface PMapOptions {
23
27
  logger?: CommonLogger | null;
24
28
  }
25
29
  /**
30
+ * Forked from https://github.com/sindresorhus/p-map
31
+ *
32
+ * Improvements:
33
+ * - Exported as { pMap }, so IDE auto-completion works
34
+ * - Included Typescript typings (no need for @types/p-map)
35
+ * - Compatible with pProps (that had typings issues)
36
+ * - Preserves async stack traces (in selected cases)
37
+ *
26
38
  * Returns a `Promise` that is fulfilled when all promises in `input` and ones returned from `mapper` are fulfilled,
27
39
  * or rejects if any of the promises reject. The fulfilled value is an `Array` of the fulfilled values returned
28
40
  * from `mapper` in `input` order.
@@ -1,16 +1,16 @@
1
1
  "use strict";
2
- /*
3
- Taken from https://github.com/sindresorhus/p-map
4
-
5
- Improvements:
6
- - Exported as { pMap }, so IDE auto-completion works
7
- - Included Typescript typings (no need for @types/p-map)
8
- - Compatible with pProps (that had typings issues)
9
- */
10
2
  Object.defineProperty(exports, "__esModule", { value: true });
11
3
  exports.pMap = void 0;
12
4
  const __1 = require("..");
13
5
  /**
6
+ * Forked from https://github.com/sindresorhus/p-map
7
+ *
8
+ * Improvements:
9
+ * - Exported as { pMap }, so IDE auto-completion works
10
+ * - Included Typescript typings (no need for @types/p-map)
11
+ * - Compatible with pProps (that had typings issues)
12
+ * - Preserves async stack traces (in selected cases)
13
+ *
14
14
  * Returns a `Promise` that is fulfilled when all promises in `input` and ones returned from `mapper` are fulfilled,
15
15
  * or rejects if any of the promises reject. The fulfilled value is an `Array` of the fulfilled values returned
16
16
  * from `mapper` in `input` order.
@@ -37,70 +37,26 @@ const __1 = require("..");
37
37
  * })();
38
38
  */
39
39
  async function pMap(iterable, mapper, opt = {}) {
40
- const { logger = console } = opt;
41
- const ret = [];
42
- // const iterator = iterable[Symbol.iterator]()
43
40
  const items = [...iterable];
44
41
  const itemsLength = items.length;
45
42
  if (itemsLength === 0)
46
43
  return []; // short circuit
47
- const { concurrency = itemsLength, errorMode = __1.ErrorMode.THROW_IMMEDIATELY } = opt;
48
- const errors = [];
49
- let isSettled = false;
50
- let resolvingCount = 0;
51
- let currentIndex = 0;
44
+ const { concurrency = 16, errorMode = __1.ErrorMode.THROW_IMMEDIATELY, logger = console } = opt;
52
45
  // Special cases that are able to preserve async stack traces
46
+ // Special case: serial execution
53
47
  if (concurrency === 1) {
54
- // Special case for concurrency == 1
55
- for (const item of items) {
56
- try {
57
- const r = await mapper(item, currentIndex++);
58
- if (r === __1.END)
59
- break;
60
- if (r !== __1.SKIP)
61
- ret.push(r);
62
- }
63
- catch (err) {
64
- if (errorMode === __1.ErrorMode.THROW_IMMEDIATELY)
65
- throw err;
66
- if (errorMode === __1.ErrorMode.THROW_AGGREGATED) {
67
- errors.push(err);
68
- }
69
- else {
70
- // otherwise, suppress (but still log via logger)
71
- logger?.error(err);
72
- }
73
- }
74
- }
75
- if (errors.length) {
76
- throw new AggregateError(errors, `pMap resulted in ${errors.length} error(s)`);
77
- }
78
- return ret;
48
+ return await pMap1(items, mapper, errorMode, logger);
79
49
  }
80
- else if (!opt.concurrency || items.length <= opt.concurrency) {
81
- // Special case for concurrency == infinity or iterable.length < concurrency
82
- if (errorMode === __1.ErrorMode.THROW_IMMEDIATELY) {
83
- return (await Promise.all(items.map((item, i) => mapper(item, i)))).filter(r => r !== __1.SKIP && r !== __1.END);
84
- }
85
- ;
86
- (await Promise.allSettled(items.map((item, i) => mapper(item, i)))).forEach(r => {
87
- if (r.status === 'fulfilled') {
88
- if (r.value !== __1.SKIP && r.value !== __1.END)
89
- ret.push(r.value);
90
- }
91
- else if (errorMode === __1.ErrorMode.THROW_AGGREGATED) {
92
- errors.push(r.reason);
93
- }
94
- else {
95
- // otherwise, suppress (but still log via logger)
96
- logger?.error(r.reason);
97
- }
98
- });
99
- if (errors.length) {
100
- throw new AggregateError(errors, `pMap resulted in ${errors.length} error(s)`);
101
- }
102
- return ret;
50
+ // Special case: concurrency === Infinity or items.length <= concurrency
51
+ if (concurrency === Infinity || items.length <= concurrency) {
52
+ return await pMapAll(items, mapper, errorMode, logger);
103
53
  }
54
+ // General case: execution with throttled concurrency
55
+ const ret = [];
56
+ const errors = [];
57
+ let isSettled = false;
58
+ let resolvingCount = 0;
59
+ let currentIndex = 0;
104
60
  return await new Promise((resolve, reject) => {
105
61
  const next = () => {
106
62
  if (isSettled) {
@@ -159,3 +115,64 @@ async function pMap(iterable, mapper, opt = {}) {
159
115
  });
160
116
  }
161
117
  exports.pMap = pMap;
118
+ /**
119
+ pMap with serial (non-concurrent) execution.
120
+ */
121
+ async function pMap1(items, mapper, errorMode, logger) {
122
+ let i = 0;
123
+ const ret = [];
124
+ const errors = [];
125
+ for (const item of items) {
126
+ try {
127
+ const r = await mapper(item, i++);
128
+ if (r === __1.END)
129
+ break;
130
+ if (r !== __1.SKIP)
131
+ ret.push(r);
132
+ }
133
+ catch (err) {
134
+ if (errorMode === __1.ErrorMode.THROW_IMMEDIATELY)
135
+ throw err;
136
+ if (errorMode === __1.ErrorMode.THROW_AGGREGATED) {
137
+ errors.push(err);
138
+ }
139
+ else {
140
+ // otherwise, suppress (but still log via logger)
141
+ logger?.error(err);
142
+ }
143
+ }
144
+ }
145
+ if (errors.length) {
146
+ throw new AggregateError(errors, `pMap resulted in ${errors.length} error(s)`);
147
+ }
148
+ return ret;
149
+ }
150
+ /**
151
+ pMap with fully concurrent execution, like Promise.all
152
+ */
153
+ async function pMapAll(items, mapper, errorMode, logger) {
154
+ if (errorMode === __1.ErrorMode.THROW_IMMEDIATELY) {
155
+ return (await Promise.all(items.map((item, i) => mapper(item, i)))).filter(r => r !== __1.SKIP && r !== __1.END);
156
+ }
157
+ const ret = [];
158
+ const errors = [];
159
+ for (const r of await Promise.allSettled(items.map((item, i) => mapper(item, i)))) {
160
+ if (r.status === 'fulfilled') {
161
+ if (r.value === __1.END)
162
+ break;
163
+ if (r.value !== __1.SKIP)
164
+ ret.push(r.value);
165
+ }
166
+ else if (errorMode === __1.ErrorMode.THROW_AGGREGATED) {
167
+ errors.push(r.reason);
168
+ }
169
+ else {
170
+ // otherwise, suppress (but still log via logger)
171
+ logger?.error(r.reason);
172
+ }
173
+ }
174
+ if (errors.length) {
175
+ throw new AggregateError(errors, `pMap resulted in ${errors.length} error(s)`);
176
+ }
177
+ return ret;
178
+ }
@@ -1,13 +1,13 @@
1
- /*
2
- Taken from https://github.com/sindresorhus/p-map
3
-
4
- Improvements:
5
- - Exported as { pMap }, so IDE auto-completion works
6
- - Included Typescript typings (no need for @types/p-map)
7
- - Compatible with pProps (that had typings issues)
8
- */
9
1
  import { END, ErrorMode, SKIP } from '..';
10
2
  /**
3
+ * Forked from https://github.com/sindresorhus/p-map
4
+ *
5
+ * Improvements:
6
+ * - Exported as { pMap }, so IDE auto-completion works
7
+ * - Included Typescript typings (no need for @types/p-map)
8
+ * - Compatible with pProps (that had typings issues)
9
+ * - Preserves async stack traces (in selected cases)
10
+ *
11
11
  * Returns a `Promise` that is fulfilled when all promises in `input` and ones returned from `mapper` are fulfilled,
12
12
  * or rejects if any of the promises reject. The fulfilled value is an `Array` of the fulfilled values returned
13
13
  * from `mapper` in `input` order.
@@ -34,70 +34,26 @@ import { END, ErrorMode, SKIP } from '..';
34
34
  * })();
35
35
  */
36
36
  export async function pMap(iterable, mapper, opt = {}) {
37
- const { logger = console } = opt;
38
- const ret = [];
39
- // const iterator = iterable[Symbol.iterator]()
40
37
  const items = [...iterable];
41
38
  const itemsLength = items.length;
42
39
  if (itemsLength === 0)
43
40
  return []; // short circuit
44
- const { concurrency = itemsLength, errorMode = ErrorMode.THROW_IMMEDIATELY } = opt;
45
- const errors = [];
46
- let isSettled = false;
47
- let resolvingCount = 0;
48
- let currentIndex = 0;
41
+ const { concurrency = 16, errorMode = ErrorMode.THROW_IMMEDIATELY, logger = console } = opt;
49
42
  // Special cases that are able to preserve async stack traces
43
+ // Special case: serial execution
50
44
  if (concurrency === 1) {
51
- // Special case for concurrency == 1
52
- for (const item of items) {
53
- try {
54
- const r = await mapper(item, currentIndex++);
55
- if (r === END)
56
- break;
57
- if (r !== SKIP)
58
- ret.push(r);
59
- }
60
- catch (err) {
61
- if (errorMode === ErrorMode.THROW_IMMEDIATELY)
62
- throw err;
63
- if (errorMode === ErrorMode.THROW_AGGREGATED) {
64
- errors.push(err);
65
- }
66
- else {
67
- // otherwise, suppress (but still log via logger)
68
- logger === null || logger === void 0 ? void 0 : logger.error(err);
69
- }
70
- }
71
- }
72
- if (errors.length) {
73
- throw new AggregateError(errors, `pMap resulted in ${errors.length} error(s)`);
74
- }
75
- return ret;
45
+ return await pMap1(items, mapper, errorMode, logger);
76
46
  }
77
- else if (!opt.concurrency || items.length <= opt.concurrency) {
78
- // Special case for concurrency == infinity or iterable.length < concurrency
79
- if (errorMode === ErrorMode.THROW_IMMEDIATELY) {
80
- return (await Promise.all(items.map((item, i) => mapper(item, i)))).filter(r => r !== SKIP && r !== END);
81
- }
82
- ;
83
- (await Promise.allSettled(items.map((item, i) => mapper(item, i)))).forEach(r => {
84
- if (r.status === 'fulfilled') {
85
- if (r.value !== SKIP && r.value !== END)
86
- ret.push(r.value);
87
- }
88
- else if (errorMode === ErrorMode.THROW_AGGREGATED) {
89
- errors.push(r.reason);
90
- }
91
- else {
92
- // otherwise, suppress (but still log via logger)
93
- logger === null || logger === void 0 ? void 0 : logger.error(r.reason);
94
- }
95
- });
96
- if (errors.length) {
97
- throw new AggregateError(errors, `pMap resulted in ${errors.length} error(s)`);
98
- }
99
- return ret;
47
+ // Special case: concurrency === Infinity or items.length <= concurrency
48
+ if (concurrency === Infinity || items.length <= concurrency) {
49
+ return await pMapAll(items, mapper, errorMode, logger);
100
50
  }
51
+ // General case: execution with throttled concurrency
52
+ const ret = [];
53
+ const errors = [];
54
+ let isSettled = false;
55
+ let resolvingCount = 0;
56
+ let currentIndex = 0;
101
57
  return await new Promise((resolve, reject) => {
102
58
  const next = () => {
103
59
  if (isSettled) {
@@ -155,3 +111,64 @@ export async function pMap(iterable, mapper, opt = {}) {
155
111
  }
156
112
  });
157
113
  }
114
+ /**
115
+ pMap with serial (non-concurrent) execution.
116
+ */
117
+ async function pMap1(items, mapper, errorMode, logger) {
118
+ let i = 0;
119
+ const ret = [];
120
+ const errors = [];
121
+ for (const item of items) {
122
+ try {
123
+ const r = await mapper(item, i++);
124
+ if (r === END)
125
+ break;
126
+ if (r !== SKIP)
127
+ ret.push(r);
128
+ }
129
+ catch (err) {
130
+ if (errorMode === ErrorMode.THROW_IMMEDIATELY)
131
+ throw err;
132
+ if (errorMode === ErrorMode.THROW_AGGREGATED) {
133
+ errors.push(err);
134
+ }
135
+ else {
136
+ // otherwise, suppress (but still log via logger)
137
+ logger === null || logger === void 0 ? void 0 : logger.error(err);
138
+ }
139
+ }
140
+ }
141
+ if (errors.length) {
142
+ throw new AggregateError(errors, `pMap resulted in ${errors.length} error(s)`);
143
+ }
144
+ return ret;
145
+ }
146
+ /**
147
+ pMap with fully concurrent execution, like Promise.all
148
+ */
149
+ async function pMapAll(items, mapper, errorMode, logger) {
150
+ if (errorMode === ErrorMode.THROW_IMMEDIATELY) {
151
+ return (await Promise.all(items.map((item, i) => mapper(item, i)))).filter(r => r !== SKIP && r !== END);
152
+ }
153
+ const ret = [];
154
+ const errors = [];
155
+ for (const r of await Promise.allSettled(items.map((item, i) => mapper(item, i)))) {
156
+ if (r.status === 'fulfilled') {
157
+ if (r.value === END)
158
+ break;
159
+ if (r.value !== SKIP)
160
+ ret.push(r.value);
161
+ }
162
+ else if (errorMode === ErrorMode.THROW_AGGREGATED) {
163
+ errors.push(r.reason);
164
+ }
165
+ else {
166
+ // otherwise, suppress (but still log via logger)
167
+ logger === null || logger === void 0 ? void 0 : logger.error(r.reason);
168
+ }
169
+ }
170
+ if (errors.length) {
171
+ throw new AggregateError(errors, `pMap resulted in ${errors.length} error(s)`);
172
+ }
173
+ return ret;
174
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@naturalcycles/js-lib",
3
- "version": "14.218.0",
3
+ "version": "14.219.0",
4
4
  "scripts": {
5
5
  "prepare": "husky",
6
6
  "build-prod": "build-prod-esm-cjs",
@@ -1,12 +1,3 @@
1
- /*
2
- Taken from https://github.com/sindresorhus/p-map
3
-
4
- Improvements:
5
- - Exported as { pMap }, so IDE auto-completion works
6
- - Included Typescript typings (no need for @types/p-map)
7
- - Compatible with pProps (that had typings issues)
8
- */
9
-
10
1
  import type { AbortableAsyncMapper, CommonLogger } from '..'
11
2
  import { END, ErrorMode, SKIP } from '..'
12
3
 
@@ -14,7 +5,11 @@ export interface PMapOptions {
14
5
  /**
15
6
  * Number of concurrently pending promises returned by `mapper`.
16
7
  *
17
- * @default Infinity
8
+ * Defaults to 16.
9
+ *
10
+ * It previously (and originally) defaulted to Infinity, which was later changed,
11
+ * because it's somewhat dangerous to run "infinite number of parallel promises".
12
+ * You can still emulate the old behavior by passing `Infinity`.
18
13
  */
19
14
  concurrency?: number
20
15
 
@@ -36,6 +31,14 @@ export interface PMapOptions {
36
31
  }
37
32
 
38
33
  /**
34
+ * Forked from https://github.com/sindresorhus/p-map
35
+ *
36
+ * Improvements:
37
+ * - Exported as { pMap }, so IDE auto-completion works
38
+ * - Included Typescript typings (no need for @types/p-map)
39
+ * - Compatible with pProps (that had typings issues)
40
+ * - Preserves async stack traces (in selected cases)
41
+ *
39
42
  * Returns a `Promise` that is fulfilled when all promises in `input` and ones returned from `mapper` are fulfilled,
40
43
  * or rejects if any of the promises reject. The fulfilled value is an `Array` of the fulfilled values returned
41
44
  * from `mapper` in `input` order.
@@ -66,73 +69,30 @@ export async function pMap<IN, OUT>(
66
69
  mapper: AbortableAsyncMapper<IN, OUT>,
67
70
  opt: PMapOptions = {},
68
71
  ): Promise<OUT[]> {
69
- const { logger = console } = opt
70
- const ret: (OUT | typeof SKIP)[] = []
71
- // const iterator = iterable[Symbol.iterator]()
72
72
  const items = [...iterable]
73
73
  const itemsLength = items.length
74
74
  if (itemsLength === 0) return [] // short circuit
75
75
 
76
- const { concurrency = itemsLength, errorMode = ErrorMode.THROW_IMMEDIATELY } = opt
77
-
78
- const errors: Error[] = []
79
- let isSettled = false
80
- let resolvingCount = 0
81
- let currentIndex = 0
76
+ const { concurrency = 16, errorMode = ErrorMode.THROW_IMMEDIATELY, logger = console } = opt
82
77
 
83
78
  // Special cases that are able to preserve async stack traces
84
-
79
+ // Special case: serial execution
85
80
  if (concurrency === 1) {
86
- // Special case for concurrency == 1
87
-
88
- for (const item of items) {
89
- try {
90
- const r = await mapper(item, currentIndex++)
91
- if (r === END) break
92
- if (r !== SKIP) ret.push(r)
93
- } catch (err) {
94
- if (errorMode === ErrorMode.THROW_IMMEDIATELY) throw err
95
- if (errorMode === ErrorMode.THROW_AGGREGATED) {
96
- errors.push(err as Error)
97
- } else {
98
- // otherwise, suppress (but still log via logger)
99
- logger?.error(err)
100
- }
101
- }
102
- }
103
-
104
- if (errors.length) {
105
- throw new AggregateError(errors, `pMap resulted in ${errors.length} error(s)`)
106
- }
107
-
108
- return ret as OUT[]
109
- } else if (!opt.concurrency || items.length <= opt.concurrency) {
110
- // Special case for concurrency == infinity or iterable.length < concurrency
111
-
112
- if (errorMode === ErrorMode.THROW_IMMEDIATELY) {
113
- return (await Promise.all(items.map((item, i) => mapper(item, i)))).filter(
114
- r => r !== SKIP && r !== END,
115
- ) as OUT[]
116
- }
117
-
118
- ;(await Promise.allSettled(items.map((item, i) => mapper(item, i)))).forEach(r => {
119
- if (r.status === 'fulfilled') {
120
- if (r.value !== SKIP && r.value !== END) ret.push(r.value)
121
- } else if (errorMode === ErrorMode.THROW_AGGREGATED) {
122
- errors.push(r.reason)
123
- } else {
124
- // otherwise, suppress (but still log via logger)
125
- logger?.error(r.reason)
126
- }
127
- })
128
-
129
- if (errors.length) {
130
- throw new AggregateError(errors, `pMap resulted in ${errors.length} error(s)`)
131
- }
81
+ return await pMap1(items, mapper, errorMode, logger)
82
+ }
132
83
 
133
- return ret as OUT[]
84
+ // Special case: concurrency === Infinity or items.length <= concurrency
85
+ if (concurrency === Infinity || items.length <= concurrency) {
86
+ return await pMapAll(items, mapper, errorMode, logger)
134
87
  }
135
88
 
89
+ // General case: execution with throttled concurrency
90
+ const ret: (OUT | typeof SKIP)[] = []
91
+ const errors: Error[] = []
92
+ let isSettled = false
93
+ let resolvingCount = 0
94
+ let currentIndex = 0
95
+
136
96
  return await new Promise<OUT[]>((resolve, reject) => {
137
97
  const next = (): void => {
138
98
  if (isSettled) {
@@ -198,3 +158,76 @@ export async function pMap<IN, OUT>(
198
158
  }
199
159
  })
200
160
  }
161
+
162
+ /**
163
+ pMap with serial (non-concurrent) execution.
164
+ */
165
+ async function pMap1<IN, OUT>(
166
+ items: IN[],
167
+ mapper: AbortableAsyncMapper<IN, OUT>,
168
+ errorMode: ErrorMode,
169
+ logger: CommonLogger | null,
170
+ ): Promise<OUT[]> {
171
+ let i = 0
172
+ const ret: OUT[] = []
173
+ const errors: Error[] = []
174
+
175
+ for (const item of items) {
176
+ try {
177
+ const r = await mapper(item, i++)
178
+ if (r === END) break
179
+ if (r !== SKIP) ret.push(r)
180
+ } catch (err) {
181
+ if (errorMode === ErrorMode.THROW_IMMEDIATELY) throw err
182
+ if (errorMode === ErrorMode.THROW_AGGREGATED) {
183
+ errors.push(err as Error)
184
+ } else {
185
+ // otherwise, suppress (but still log via logger)
186
+ logger?.error(err)
187
+ }
188
+ }
189
+ }
190
+
191
+ if (errors.length) {
192
+ throw new AggregateError(errors, `pMap resulted in ${errors.length} error(s)`)
193
+ }
194
+
195
+ return ret
196
+ }
197
+
198
+ /**
199
+ pMap with fully concurrent execution, like Promise.all
200
+ */
201
+ async function pMapAll<IN, OUT>(
202
+ items: IN[],
203
+ mapper: AbortableAsyncMapper<IN, OUT>,
204
+ errorMode: ErrorMode,
205
+ logger: CommonLogger | null,
206
+ ): Promise<OUT[]> {
207
+ if (errorMode === ErrorMode.THROW_IMMEDIATELY) {
208
+ return (await Promise.all(items.map((item, i) => mapper(item, i)))).filter(
209
+ r => r !== SKIP && r !== END,
210
+ ) as OUT[]
211
+ }
212
+
213
+ const ret: OUT[] = []
214
+ const errors: Error[] = []
215
+
216
+ for (const r of await Promise.allSettled(items.map((item, i) => mapper(item, i)))) {
217
+ if (r.status === 'fulfilled') {
218
+ if (r.value === END) break
219
+ if (r.value !== SKIP) ret.push(r.value)
220
+ } else if (errorMode === ErrorMode.THROW_AGGREGATED) {
221
+ errors.push(r.reason)
222
+ } else {
223
+ // otherwise, suppress (but still log via logger)
224
+ logger?.error(r.reason)
225
+ }
226
+ }
227
+
228
+ if (errors.length) {
229
+ throw new AggregateError(errors, `pMap resulted in ${errors.length} error(s)`)
230
+ }
231
+
232
+ return ret
233
+ }