@naturalcycles/nodejs-lib 15.18.1 → 15.20.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/exec2/exec2.js +19 -7
- package/dist/stream/index.d.ts +1 -0
- package/dist/stream/index.js +1 -0
- package/dist/stream/ndjson/ndjsonMap.d.ts +0 -6
- package/dist/stream/ndjson/ndjsonMap.js +2 -2
- package/dist/stream/progressLogger.js +3 -6
- package/dist/stream/transform/transformFlatten.d.ts +2 -0
- package/dist/stream/transform/transformFlatten.js +18 -0
- package/dist/stream/transform/transformMap.d.ts +0 -6
- package/dist/stream/transform/transformMap.js +13 -34
- package/dist/stream/transform/transformMapSync.d.ts +0 -5
- package/dist/stream/transform/transformMapSync.js +12 -14
- package/package.json +2 -2
- package/src/exec2/exec2.ts +23 -9
- package/src/stream/index.ts +1 -0
- package/src/stream/ndjson/ndjsonMap.ts +2 -8
- package/src/stream/progressLogger.ts +3 -7
- package/src/stream/transform/transformFlatten.ts +19 -0
- package/src/stream/transform/transformMap.ts +14 -42
- package/src/stream/transform/transformMapSync.ts +13 -25
package/dist/exec2/exec2.js
CHANGED
|
@@ -241,18 +241,30 @@ class Exec2 {
|
|
|
241
241
|
logStart(cmd, opt) {
|
|
242
242
|
if (!opt.logStart)
|
|
243
243
|
return;
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
244
|
+
const envString = Object.entries(opt.env || {})
|
|
245
|
+
.map(([k, v]) => [k, v].join('='))
|
|
246
|
+
.join(' ');
|
|
247
|
+
if (opt.name) {
|
|
248
|
+
console.log([' ', dimGrey(envString), white(opt.name), dimGrey('started...')]
|
|
249
|
+
.filter(Boolean)
|
|
250
|
+
.join(' '));
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
console.log([
|
|
254
|
+
' ',
|
|
255
|
+
dimGrey(envString),
|
|
256
|
+
white(_substringAfterLast(cmd, '/')),
|
|
257
|
+
...(opt.args || []),
|
|
258
|
+
]
|
|
259
|
+
.filter(Boolean)
|
|
260
|
+
.join(' '));
|
|
261
|
+
}
|
|
251
262
|
}
|
|
252
263
|
logFinish(cmd, opt, started, isSuccessful) {
|
|
253
264
|
if (isSuccessful && !opt.logFinish)
|
|
254
265
|
return;
|
|
255
266
|
console.log([
|
|
267
|
+
isSuccessful ? '✔️ ' : '❌',
|
|
256
268
|
white(opt.name || _substringAfterLast(cmd, '/')),
|
|
257
269
|
...((!opt.name && opt.args) || []),
|
|
258
270
|
dimGrey('took ' + _since(started)),
|
package/dist/stream/index.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ export * from './readable/readableToArray.js';
|
|
|
14
14
|
export * from './stream.model.js';
|
|
15
15
|
export * from './transform/transformChunk.js';
|
|
16
16
|
export * from './transform/transformFilter.js';
|
|
17
|
+
export * from './transform/transformFlatten.js';
|
|
17
18
|
export * from './transform/transformLimit.js';
|
|
18
19
|
export * from './transform/transformLogProgress.js';
|
|
19
20
|
export * from './transform/transformMap.js';
|
package/dist/stream/index.js
CHANGED
|
@@ -14,6 +14,7 @@ export * from './readable/readableToArray.js';
|
|
|
14
14
|
export * from './stream.model.js';
|
|
15
15
|
export * from './transform/transformChunk.js';
|
|
16
16
|
export * from './transform/transformFilter.js';
|
|
17
|
+
export * from './transform/transformFlatten.js';
|
|
17
18
|
export * from './transform/transformLimit.js';
|
|
18
19
|
export * from './transform/transformLogProgress.js';
|
|
19
20
|
export * from './transform/transformMap.js';
|
|
@@ -9,12 +9,6 @@ export interface NDJSONMapOptions<IN = any, OUT = IN> extends TransformMapOption
|
|
|
9
9
|
* @default 100_000
|
|
10
10
|
*/
|
|
11
11
|
logEveryOutput?: number;
|
|
12
|
-
/**
|
|
13
|
-
* Defaults to `true` for ndjsonMap
|
|
14
|
-
*
|
|
15
|
-
* @default true
|
|
16
|
-
*/
|
|
17
|
-
flattenArrayOutput?: boolean;
|
|
18
12
|
}
|
|
19
13
|
/**
|
|
20
14
|
* Unzips input file automatically, if it ends with `.gz`.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ErrorMode } from '@naturalcycles/js-lib/error/errorMode.js';
|
|
2
|
-
import { createReadStreamAsNDJSON, createWriteStreamAsNDJSON, } from '../index.js';
|
|
2
|
+
import { createReadStreamAsNDJSON, createWriteStreamAsNDJSON, transformFlatten, } from '../index.js';
|
|
3
3
|
import { _pipeline, transformLimit, transformLogProgress, transformMap } from '../index.js';
|
|
4
4
|
/**
|
|
5
5
|
* Unzips input file automatically, if it ends with `.gz`.
|
|
@@ -16,10 +16,10 @@ export async function ndjsonMap(mapper, opt) {
|
|
|
16
16
|
readable,
|
|
17
17
|
transformLogProgress({ metric: 'read', ...opt }),
|
|
18
18
|
transformMap(mapper, {
|
|
19
|
-
flattenArrayOutput: true,
|
|
20
19
|
errorMode: ErrorMode.SUPPRESS,
|
|
21
20
|
...opt,
|
|
22
21
|
}),
|
|
22
|
+
transformFlatten(),
|
|
23
23
|
transformLimit({ limit: limitOutput, sourceReadable: readable }),
|
|
24
24
|
transformLogProgress({ metric: 'saved', logEvery: logEveryOutput }),
|
|
25
25
|
...createWriteStreamAsNDJSON(outputFilePath),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { inspect } from 'node:util';
|
|
2
|
-
import { _mb } from '@naturalcycles/js-lib';
|
|
2
|
+
import { _hc, _mb } from '@naturalcycles/js-lib';
|
|
3
3
|
import { _since, localTime } from '@naturalcycles/js-lib/datetime';
|
|
4
4
|
import { SimpleMovingAverage } from '@naturalcycles/js-lib/math';
|
|
5
5
|
import { boldWhite, dimGrey, hasColors, white, yellow } from '../colors/colors.js';
|
|
@@ -108,11 +108,8 @@ export class ProgressLogger {
|
|
|
108
108
|
}
|
|
109
109
|
}
|
|
110
110
|
if (tenx) {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
perHour = Math.round(perHour / 1000) + 'K';
|
|
114
|
-
}
|
|
115
|
-
logger.log(`${dimGrey(localTime.now().toPretty())} ${white(metric)} took ${yellow(_since(this.started))} so far to process ${yellow(batchedProgress)} rows, ~${yellow(perHour)}/hour`);
|
|
111
|
+
const perHour = _hc((batchedProgress * 1000 * 60 * 60) / (now - this.started));
|
|
112
|
+
logger.log(`${dimGrey(localTime.now().toPretty())} ${white(metric)} took ${yellow(_since(this.started))} so far to process ${yellow(_hc(batchedProgress))} rows, ~${yellow(perHour)}/hour`);
|
|
116
113
|
}
|
|
117
114
|
else if (final) {
|
|
118
115
|
logger.log(`${boldWhite(metric)} took ${yellow(_since(this.started))} to process ${yellow(batchedProgress)} rows with total RPS of ${yellow(rpsTotal)}`);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Transform } from 'node:stream';
|
|
2
|
+
export function transformFlatten() {
|
|
3
|
+
return new Transform({
|
|
4
|
+
objectMode: true,
|
|
5
|
+
transform(chunk, _, cb) {
|
|
6
|
+
if (!Array.isArray(chunk)) {
|
|
7
|
+
// As a safety precaution, to not crash the pipeline - push as is
|
|
8
|
+
this.push(chunk);
|
|
9
|
+
}
|
|
10
|
+
else {
|
|
11
|
+
for (const item of chunk) {
|
|
12
|
+
this.push(item);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
cb(); // acknowledge
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
}
|
|
@@ -3,12 +3,6 @@ import type { CommonLogger } from '@naturalcycles/js-lib/log';
|
|
|
3
3
|
import { type AbortableAsyncMapper, type AsyncPredicate, END, type Promisable, SKIP, type StringMap, type UnixTimestampMillis } from '@naturalcycles/js-lib/types';
|
|
4
4
|
import type { TransformTyped } from '../stream.model.js';
|
|
5
5
|
export interface TransformMapOptions<IN = any, OUT = IN> {
|
|
6
|
-
/**
|
|
7
|
-
* Set true to support "multiMap" - possibility to return [] and emit 1 result for each item in the array.
|
|
8
|
-
*
|
|
9
|
-
* @default false
|
|
10
|
-
*/
|
|
11
|
-
flattenArrayOutput?: boolean;
|
|
12
6
|
/**
|
|
13
7
|
* Predicate to filter outgoing results (after mapper).
|
|
14
8
|
* Allows to not emit all results.
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { _hc } from '@naturalcycles/js-lib';
|
|
2
2
|
import { _since } from '@naturalcycles/js-lib/datetime/time.util.js';
|
|
3
3
|
import { _anyToError, ErrorMode } from '@naturalcycles/js-lib/error';
|
|
4
|
-
import { pMap } from '@naturalcycles/js-lib/promise/pMap.js';
|
|
5
4
|
import { _stringify } from '@naturalcycles/js-lib/string/stringify.js';
|
|
6
5
|
import { END, SKIP, } from '@naturalcycles/js-lib/types';
|
|
7
6
|
import through2Concurrent from 'through2-concurrent';
|
|
@@ -23,7 +22,7 @@ import { pipelineClose } from '../stream.util.js';
|
|
|
23
22
|
*/
|
|
24
23
|
export function transformMap(mapper, opt = {}) {
|
|
25
24
|
const { concurrency = 16, predicate, // we now default to "no predicate" (meaning pass-everything)
|
|
26
|
-
errorMode = ErrorMode.THROW_IMMEDIATELY,
|
|
25
|
+
errorMode = ErrorMode.THROW_IMMEDIATELY, onError, onDone, metric = 'stream', logger = console, } = opt;
|
|
27
26
|
const started = Date.now();
|
|
28
27
|
let index = -1;
|
|
29
28
|
let countOut = 0;
|
|
@@ -80,40 +79,20 @@ export function transformMap(mapper, opt = {}) {
|
|
|
80
79
|
// Check for isSettled again, as it may happen while mapper was running
|
|
81
80
|
if (isSettled)
|
|
82
81
|
return cb();
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
const resInput = (flattenArrayOutput && Array.isArray(res) ? res : [res]);
|
|
86
|
-
if (predicate) {
|
|
87
|
-
await pMap(resInput, async (r) => {
|
|
88
|
-
if (r === END) {
|
|
89
|
-
isSettled = true; // will be checked later
|
|
90
|
-
return END;
|
|
91
|
-
}
|
|
92
|
-
if (r === SKIP)
|
|
93
|
-
return;
|
|
94
|
-
if (await predicate(r, currentIndex)) {
|
|
95
|
-
if (isSettled)
|
|
96
|
-
return END; // isSettled could have happened in parallel
|
|
97
|
-
countOut++;
|
|
98
|
-
this.push(r);
|
|
99
|
-
}
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
else {
|
|
103
|
-
for (const r of resInput) {
|
|
104
|
-
if (r === END) {
|
|
105
|
-
isSettled = true; // will be checked later
|
|
106
|
-
break;
|
|
107
|
-
}
|
|
108
|
-
if (r === SKIP)
|
|
109
|
-
continue;
|
|
110
|
-
countOut++;
|
|
111
|
-
this.push(r);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
if (isSettled) {
|
|
82
|
+
if (res === END) {
|
|
83
|
+
isSettled = true;
|
|
115
84
|
logger.log(`transformMap END received at index ${currentIndex}`);
|
|
116
85
|
pipelineClose('transformMap', this, this.sourceReadable, this.streamDone, logger);
|
|
86
|
+
return cb();
|
|
87
|
+
}
|
|
88
|
+
if (res === SKIP) {
|
|
89
|
+
// do nothing, don't push
|
|
90
|
+
return cb();
|
|
91
|
+
}
|
|
92
|
+
if (!predicate || ((await predicate(res, currentIndex)) && !isSettled)) {
|
|
93
|
+
// isSettled could have happened in parallel, hence the extra check
|
|
94
|
+
countOut++;
|
|
95
|
+
this.push(res);
|
|
117
96
|
}
|
|
118
97
|
cb(); // done processing
|
|
119
98
|
}
|
|
@@ -10,11 +10,6 @@ export interface TransformMapSyncOptions<IN = any, OUT = IN> {
|
|
|
10
10
|
* @default true
|
|
11
11
|
*/
|
|
12
12
|
objectMode?: boolean;
|
|
13
|
-
/**
|
|
14
|
-
* @default false
|
|
15
|
-
* Set true to support "multiMap" - possibility to return [] and emit 1 result for each item in the array.
|
|
16
|
-
*/
|
|
17
|
-
flattenArrayOutput?: boolean;
|
|
18
13
|
/**
|
|
19
14
|
* Predicate to filter outgoing results (after mapper).
|
|
20
15
|
* Allows to not emit all results.
|
|
@@ -11,7 +11,7 @@ export class TransformMapSync extends AbortableTransform {
|
|
|
11
11
|
*/
|
|
12
12
|
export function transformMapSync(mapper, opt = {}) {
|
|
13
13
|
const { predicate, // defaults to "no predicate" (pass everything)
|
|
14
|
-
errorMode = ErrorMode.THROW_IMMEDIATELY,
|
|
14
|
+
errorMode = ErrorMode.THROW_IMMEDIATELY, onError, onDone, metric = 'stream', objectMode = true, logger = console, } = opt;
|
|
15
15
|
const started = Date.now();
|
|
16
16
|
let index = -1;
|
|
17
17
|
let countOut = 0;
|
|
@@ -29,21 +29,19 @@ export function transformMapSync(mapper, opt = {}) {
|
|
|
29
29
|
try {
|
|
30
30
|
// map and pass through
|
|
31
31
|
const v = mapper(chunk, currentIndex);
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
for (const r of vInput) {
|
|
35
|
-
if (r === END) {
|
|
36
|
-
isSettled = true; // will be checked later
|
|
37
|
-
break;
|
|
38
|
-
}
|
|
39
|
-
if (r !== SKIP && (!predicate || predicate(r, currentIndex))) {
|
|
40
|
-
countOut++;
|
|
41
|
-
this.push(r);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
if (isSettled) {
|
|
32
|
+
if (v === END) {
|
|
33
|
+
isSettled = true; // will be checked later
|
|
45
34
|
logger.log(`transformMapSync END received at index ${currentIndex}`);
|
|
46
35
|
pipelineClose('transformMapSync', this, this.sourceReadable, this.streamDone, logger);
|
|
36
|
+
return cb();
|
|
37
|
+
}
|
|
38
|
+
if (v === SKIP) {
|
|
39
|
+
// do nothing, don't push
|
|
40
|
+
return cb();
|
|
41
|
+
}
|
|
42
|
+
if (!predicate || predicate(v, currentIndex)) {
|
|
43
|
+
countOut++;
|
|
44
|
+
this.push(v);
|
|
47
45
|
}
|
|
48
46
|
cb(); // done processing
|
|
49
47
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@naturalcycles/nodejs-lib",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "15.
|
|
4
|
+
"version": "15.20.0",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@naturalcycles/js-lib": "^15",
|
|
7
7
|
"@types/js-yaml": "^4",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@types/through2-concurrent": "^2",
|
|
26
|
-
"@naturalcycles/dev-lib": "19.
|
|
26
|
+
"@naturalcycles/dev-lib": "19.31.0"
|
|
27
27
|
},
|
|
28
28
|
"exports": {
|
|
29
29
|
".": "./dist/index.js",
|
package/src/exec2/exec2.ts
CHANGED
|
@@ -271,15 +271,28 @@ class Exec2 {
|
|
|
271
271
|
private logStart(cmd: string, opt: SpawnOptions | ExecOptions): void {
|
|
272
272
|
if (!opt.logStart) return
|
|
273
273
|
|
|
274
|
-
|
|
275
|
-
[
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
.
|
|
281
|
-
|
|
282
|
-
|
|
274
|
+
const envString = Object.entries(opt.env || {})
|
|
275
|
+
.map(([k, v]) => [k, v].join('='))
|
|
276
|
+
.join(' ')
|
|
277
|
+
|
|
278
|
+
if (opt.name) {
|
|
279
|
+
console.log(
|
|
280
|
+
[' ', dimGrey(envString), white(opt.name), dimGrey('started...')]
|
|
281
|
+
.filter(Boolean)
|
|
282
|
+
.join(' '),
|
|
283
|
+
)
|
|
284
|
+
} else {
|
|
285
|
+
console.log(
|
|
286
|
+
[
|
|
287
|
+
' ',
|
|
288
|
+
dimGrey(envString),
|
|
289
|
+
white(_substringAfterLast(cmd, '/')),
|
|
290
|
+
...((opt as SpawnOptions).args || []),
|
|
291
|
+
]
|
|
292
|
+
.filter(Boolean)
|
|
293
|
+
.join(' '),
|
|
294
|
+
)
|
|
295
|
+
}
|
|
283
296
|
}
|
|
284
297
|
|
|
285
298
|
private logFinish(
|
|
@@ -292,6 +305,7 @@ class Exec2 {
|
|
|
292
305
|
|
|
293
306
|
console.log(
|
|
294
307
|
[
|
|
308
|
+
isSuccessful ? '✔️ ' : '❌',
|
|
295
309
|
white(opt.name || _substringAfterLast(cmd, '/')),
|
|
296
310
|
...((!opt.name && (opt as SpawnOptions).args) || []),
|
|
297
311
|
dimGrey('took ' + _since(started)),
|
package/src/stream/index.ts
CHANGED
|
@@ -14,6 +14,7 @@ export * from './readable/readableToArray.js'
|
|
|
14
14
|
export * from './stream.model.js'
|
|
15
15
|
export * from './transform/transformChunk.js'
|
|
16
16
|
export * from './transform/transformFilter.js'
|
|
17
|
+
export * from './transform/transformFlatten.js'
|
|
17
18
|
export * from './transform/transformLimit.js'
|
|
18
19
|
export * from './transform/transformLogProgress.js'
|
|
19
20
|
export * from './transform/transformMap.js'
|
|
@@ -3,6 +3,7 @@ import type { AbortableAsyncMapper } from '@naturalcycles/js-lib/types'
|
|
|
3
3
|
import {
|
|
4
4
|
createReadStreamAsNDJSON,
|
|
5
5
|
createWriteStreamAsNDJSON,
|
|
6
|
+
transformFlatten,
|
|
6
7
|
type TransformLogProgressOptions,
|
|
7
8
|
type TransformMapOptions,
|
|
8
9
|
} from '../index.js'
|
|
@@ -21,13 +22,6 @@ export interface NDJSONMapOptions<IN = any, OUT = IN>
|
|
|
21
22
|
* @default 100_000
|
|
22
23
|
*/
|
|
23
24
|
logEveryOutput?: number
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Defaults to `true` for ndjsonMap
|
|
27
|
-
*
|
|
28
|
-
* @default true
|
|
29
|
-
*/
|
|
30
|
-
flattenArrayOutput?: boolean
|
|
31
25
|
}
|
|
32
26
|
|
|
33
27
|
/**
|
|
@@ -53,10 +47,10 @@ export async function ndjsonMap<IN = any, OUT = any>(
|
|
|
53
47
|
readable,
|
|
54
48
|
transformLogProgress({ metric: 'read', ...opt }),
|
|
55
49
|
transformMap(mapper, {
|
|
56
|
-
flattenArrayOutput: true,
|
|
57
50
|
errorMode: ErrorMode.SUPPRESS,
|
|
58
51
|
...opt,
|
|
59
52
|
}),
|
|
53
|
+
transformFlatten(),
|
|
60
54
|
transformLimit({ limit: limitOutput, sourceReadable: readable }),
|
|
61
55
|
transformLogProgress({ metric: 'saved', logEvery: logEveryOutput }),
|
|
62
56
|
...createWriteStreamAsNDJSON(outputFilePath),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { InspectOptions } from 'node:util'
|
|
2
2
|
import { inspect } from 'node:util'
|
|
3
|
-
import { _mb } from '@naturalcycles/js-lib'
|
|
3
|
+
import { _hc, _mb } from '@naturalcycles/js-lib'
|
|
4
4
|
import { _since, localTime } from '@naturalcycles/js-lib/datetime'
|
|
5
5
|
import type { CommonLogger } from '@naturalcycles/js-lib/log'
|
|
6
6
|
import { SimpleMovingAverage } from '@naturalcycles/js-lib/math'
|
|
@@ -284,16 +284,12 @@ export class ProgressLogger<T> implements Disposable {
|
|
|
284
284
|
}
|
|
285
285
|
|
|
286
286
|
if (tenx) {
|
|
287
|
-
|
|
288
|
-
Math.round((batchedProgress * 1000 * 60 * 60) / (now - this.started)) || 0
|
|
289
|
-
if (perHour > 900) {
|
|
290
|
-
perHour = Math.round(perHour / 1000) + 'K'
|
|
291
|
-
}
|
|
287
|
+
const perHour = _hc((batchedProgress * 1000 * 60 * 60) / (now - this.started))
|
|
292
288
|
|
|
293
289
|
logger.log(
|
|
294
290
|
`${dimGrey(localTime.now().toPretty())} ${white(metric)} took ${yellow(
|
|
295
291
|
_since(this.started),
|
|
296
|
-
)} so far to process ${yellow(batchedProgress)} rows, ~${yellow(perHour)}/hour`,
|
|
292
|
+
)} so far to process ${yellow(_hc(batchedProgress))} rows, ~${yellow(perHour)}/hour`,
|
|
297
293
|
)
|
|
298
294
|
} else if (final) {
|
|
299
295
|
logger.log(
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Transform } from 'node:stream'
|
|
2
|
+
import type { TransformTyped } from '../stream.model.js'
|
|
3
|
+
|
|
4
|
+
export function transformFlatten<T>(): TransformTyped<T[], T> {
|
|
5
|
+
return new Transform({
|
|
6
|
+
objectMode: true,
|
|
7
|
+
transform(chunk: T[], _, cb) {
|
|
8
|
+
if (!Array.isArray(chunk)) {
|
|
9
|
+
// As a safety precaution, to not crash the pipeline - push as is
|
|
10
|
+
this.push(chunk)
|
|
11
|
+
} else {
|
|
12
|
+
for (const item of chunk) {
|
|
13
|
+
this.push(item)
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
cb() // acknowledge
|
|
17
|
+
},
|
|
18
|
+
})
|
|
19
|
+
}
|
|
@@ -2,7 +2,6 @@ import { _hc } from '@naturalcycles/js-lib'
|
|
|
2
2
|
import { _since } from '@naturalcycles/js-lib/datetime/time.util.js'
|
|
3
3
|
import { _anyToError, ErrorMode } from '@naturalcycles/js-lib/error'
|
|
4
4
|
import type { CommonLogger } from '@naturalcycles/js-lib/log'
|
|
5
|
-
import { pMap } from '@naturalcycles/js-lib/promise/pMap.js'
|
|
6
5
|
import { _stringify } from '@naturalcycles/js-lib/string/stringify.js'
|
|
7
6
|
import {
|
|
8
7
|
type AbortableAsyncMapper,
|
|
@@ -20,13 +19,6 @@ import type { TransformTyped } from '../stream.model.js'
|
|
|
20
19
|
import { pipelineClose } from '../stream.util.js'
|
|
21
20
|
|
|
22
21
|
export interface TransformMapOptions<IN = any, OUT = IN> {
|
|
23
|
-
/**
|
|
24
|
-
* Set true to support "multiMap" - possibility to return [] and emit 1 result for each item in the array.
|
|
25
|
-
*
|
|
26
|
-
* @default false
|
|
27
|
-
*/
|
|
28
|
-
flattenArrayOutput?: boolean
|
|
29
|
-
|
|
30
22
|
/**
|
|
31
23
|
* Predicate to filter outgoing results (after mapper).
|
|
32
24
|
* Allows to not emit all results.
|
|
@@ -133,7 +125,6 @@ export function transformMap<IN = any, OUT = IN>(
|
|
|
133
125
|
concurrency = 16,
|
|
134
126
|
predicate, // we now default to "no predicate" (meaning pass-everything)
|
|
135
127
|
errorMode = ErrorMode.THROW_IMMEDIATELY,
|
|
136
|
-
flattenArrayOutput,
|
|
137
128
|
onError,
|
|
138
129
|
onDone,
|
|
139
130
|
metric = 'stream',
|
|
@@ -206,42 +197,23 @@ export function transformMap<IN = any, OUT = IN>(
|
|
|
206
197
|
const res: OUT | typeof SKIP | typeof END = await mapper(chunk, currentIndex)
|
|
207
198
|
// Check for isSettled again, as it may happen while mapper was running
|
|
208
199
|
if (isSettled) return cb()
|
|
209
|
-
// todo: consider retiring flattenArrayOutput from here
|
|
210
|
-
// and implementing it as a separate .flat transform/operator
|
|
211
|
-
const resInput = (flattenArrayOutput && Array.isArray(res) ? res : [res]) as (
|
|
212
|
-
| OUT
|
|
213
|
-
| typeof SKIP
|
|
214
|
-
| typeof END
|
|
215
|
-
)[]
|
|
216
|
-
|
|
217
|
-
if (predicate) {
|
|
218
|
-
await pMap(resInput, async r => {
|
|
219
|
-
if (r === END) {
|
|
220
|
-
isSettled = true // will be checked later
|
|
221
|
-
return END
|
|
222
|
-
}
|
|
223
|
-
if (r === SKIP) return
|
|
224
|
-
if (await predicate(r, currentIndex)) {
|
|
225
|
-
if (isSettled) return END // isSettled could have happened in parallel
|
|
226
|
-
countOut++
|
|
227
|
-
this.push(r)
|
|
228
|
-
}
|
|
229
|
-
})
|
|
230
|
-
} else {
|
|
231
|
-
for (const r of resInput) {
|
|
232
|
-
if (r === END) {
|
|
233
|
-
isSettled = true // will be checked later
|
|
234
|
-
break
|
|
235
|
-
}
|
|
236
|
-
if (r === SKIP) continue
|
|
237
|
-
countOut++
|
|
238
|
-
this.push(r)
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
200
|
|
|
242
|
-
if (
|
|
201
|
+
if (res === END) {
|
|
202
|
+
isSettled = true
|
|
243
203
|
logger.log(`transformMap END received at index ${currentIndex}`)
|
|
244
204
|
pipelineClose('transformMap', this, this.sourceReadable, this.streamDone, logger)
|
|
205
|
+
return cb()
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (res === SKIP) {
|
|
209
|
+
// do nothing, don't push
|
|
210
|
+
return cb()
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (!predicate || ((await predicate(res, currentIndex)) && !isSettled)) {
|
|
214
|
+
// isSettled could have happened in parallel, hence the extra check
|
|
215
|
+
countOut++
|
|
216
|
+
this.push(res)
|
|
245
217
|
}
|
|
246
218
|
|
|
247
219
|
cb() // done processing
|
|
@@ -14,12 +14,6 @@ export interface TransformMapSyncOptions<IN = any, OUT = IN> {
|
|
|
14
14
|
*/
|
|
15
15
|
objectMode?: boolean
|
|
16
16
|
|
|
17
|
-
/**
|
|
18
|
-
* @default false
|
|
19
|
-
* Set true to support "multiMap" - possibility to return [] and emit 1 result for each item in the array.
|
|
20
|
-
*/
|
|
21
|
-
flattenArrayOutput?: boolean
|
|
22
|
-
|
|
23
17
|
/**
|
|
24
18
|
* Predicate to filter outgoing results (after mapper).
|
|
25
19
|
* Allows to not emit all results.
|
|
@@ -75,7 +69,6 @@ export function transformMapSync<IN = any, OUT = IN>(
|
|
|
75
69
|
const {
|
|
76
70
|
predicate, // defaults to "no predicate" (pass everything)
|
|
77
71
|
errorMode = ErrorMode.THROW_IMMEDIATELY,
|
|
78
|
-
flattenArrayOutput = false,
|
|
79
72
|
onError,
|
|
80
73
|
onDone,
|
|
81
74
|
metric = 'stream',
|
|
@@ -102,27 +95,22 @@ export function transformMapSync<IN = any, OUT = IN>(
|
|
|
102
95
|
try {
|
|
103
96
|
// map and pass through
|
|
104
97
|
const v = mapper(chunk, currentIndex)
|
|
105
|
-
// todo: consider retiring flattenArrayOutput option
|
|
106
|
-
const vInput = (flattenArrayOutput && Array.isArray(v) ? v : [v]) as (
|
|
107
|
-
| OUT
|
|
108
|
-
| typeof SKIP
|
|
109
|
-
| typeof END
|
|
110
|
-
)[]
|
|
111
|
-
|
|
112
|
-
for (const r of vInput) {
|
|
113
|
-
if (r === END) {
|
|
114
|
-
isSettled = true // will be checked later
|
|
115
|
-
break
|
|
116
|
-
}
|
|
117
|
-
if (r !== SKIP && (!predicate || predicate(r, currentIndex))) {
|
|
118
|
-
countOut++
|
|
119
|
-
this.push(r)
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
98
|
|
|
123
|
-
if (
|
|
99
|
+
if (v === END) {
|
|
100
|
+
isSettled = true // will be checked later
|
|
124
101
|
logger.log(`transformMapSync END received at index ${currentIndex}`)
|
|
125
102
|
pipelineClose('transformMapSync', this, this.sourceReadable, this.streamDone, logger)
|
|
103
|
+
return cb()
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (v === SKIP) {
|
|
107
|
+
// do nothing, don't push
|
|
108
|
+
return cb()
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (!predicate || predicate(v, currentIndex)) {
|
|
112
|
+
countOut++
|
|
113
|
+
this.push(v)
|
|
126
114
|
}
|
|
127
115
|
|
|
128
116
|
cb() // done processing
|