@naturalcycles/nodejs-lib 15.22.0 → 15.24.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 +1 -0
- package/dist/stream/index.d.ts +1 -2
- package/dist/stream/index.js +1 -2
- package/dist/stream/ndjson/ndjsonMap.d.ts +1 -1
- package/dist/stream/ndjson/ndjsonMap.js +13 -15
- package/dist/stream/ndjson/ndjsonStreamForEach.d.ts +2 -2
- package/dist/stream/ndjson/ndjsonStreamForEach.js +9 -15
- package/dist/stream/pipeline.d.ts +93 -0
- package/dist/stream/pipeline.js +262 -0
- package/dist/stream/stream.util.d.ts +1 -3
- package/dist/stream/stream.util.js +1 -20
- package/dist/stream/transform/transformChunk.d.ts +5 -8
- package/dist/stream/transform/transformChunk.js +4 -2
- package/dist/stream/transform/transformFlatten.d.ts +1 -0
- package/dist/stream/transform/transformFlatten.js +15 -4
- package/dist/stream/transform/transformLimit.d.ts +3 -26
- package/dist/stream/transform/transformLimit.js +14 -23
- package/dist/stream/transform/transformMap.d.ts +5 -0
- package/dist/stream/transform/transformMap.js +22 -18
- package/dist/stream/transform/transformMapSync.d.ts +5 -3
- package/dist/stream/transform/transformMapSync.js +7 -8
- package/dist/stream/transform/transformSplit.js +2 -1
- package/dist/stream/transform/transformTee.js +4 -2
- package/dist/stream/writable/writableForEach.d.ts +2 -1
- package/dist/stream/writable/writableFork.js +2 -2
- package/package.json +1 -1
- package/src/exec2/exec2.ts +1 -0
- package/src/stream/index.ts +1 -2
- package/src/stream/ndjson/ndjsonMap.ts +12 -22
- package/src/stream/ndjson/ndjsonStreamForEach.ts +8 -15
- package/src/stream/pipeline.ts +351 -0
- package/src/stream/stream.util.ts +1 -29
- package/src/stream/transform/transformChunk.ts +8 -11
- package/src/stream/transform/transformFlatten.ts +16 -4
- package/src/stream/transform/transformLimit.ts +20 -51
- package/src/stream/transform/transformMap.ts +31 -20
- package/src/stream/transform/transformMapSync.ts +14 -8
- package/src/stream/transform/transformSplit.ts +2 -1
- package/src/stream/transform/transformTee.ts +5 -2
- package/src/stream/writable/writableForEach.ts +2 -2
- package/src/stream/writable/writableFork.ts +2 -2
- package/dist/stream/pipeline/pipeline.d.ts +0 -36
- package/dist/stream/pipeline/pipeline.js +0 -82
- package/dist/stream/readable/readableForEach.d.ts +0 -19
- package/dist/stream/readable/readableForEach.js +0 -30
- package/src/stream/pipeline/pipeline.ts +0 -114
- package/src/stream/readable/readableForEach.ts +0 -42
|
@@ -1,41 +1,32 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { Transform } from 'node:stream';
|
|
2
|
+
import { PIPELINE_GRACEFUL_ABORT } from '../stream.util.js';
|
|
3
3
|
import { transformNoOp } from './transformNoOp.js';
|
|
4
|
-
/**
|
|
5
|
-
* Class only exists to be able to do `instanceof TransformLimit`
|
|
6
|
-
* and to set sourceReadable+streamDone to it in `_pipeline`.
|
|
7
|
-
*/
|
|
8
|
-
export class TransformLimit extends AbortableTransform {
|
|
9
|
-
}
|
|
10
4
|
export function transformLimit(opt) {
|
|
11
|
-
const {
|
|
5
|
+
const { limit, signal } = opt;
|
|
12
6
|
if (!limit) {
|
|
13
|
-
// No limit - returning pass-through transform
|
|
14
7
|
return transformNoOp();
|
|
15
8
|
}
|
|
16
9
|
let i = 0; // so we start first chunk with 1
|
|
17
10
|
let ended = false;
|
|
18
|
-
return new
|
|
11
|
+
return new Transform({
|
|
19
12
|
objectMode: true,
|
|
20
13
|
...opt,
|
|
21
14
|
transform(chunk, _, cb) {
|
|
15
|
+
if (ended) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
22
18
|
i++;
|
|
23
19
|
if (i === limit) {
|
|
24
20
|
ended = true;
|
|
25
|
-
logger.log(`transformLimit of ${limit} reached`);
|
|
26
21
|
this.push(chunk);
|
|
27
|
-
|
|
28
|
-
cb();
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
else {
|
|
34
|
-
if (debug)
|
|
35
|
-
logger.log(`transformLimit.transform after limit`, i);
|
|
36
|
-
// If we ever HANG (don't call cb) - Node will do process.exit(0) to us
|
|
37
|
-
cb(); // ended, don't emit anything
|
|
22
|
+
this.push(null); // tell downstream that we're done
|
|
23
|
+
cb();
|
|
24
|
+
queueMicrotask(() => {
|
|
25
|
+
signal.abort(new Error(PIPELINE_GRACEFUL_ABORT));
|
|
26
|
+
});
|
|
27
|
+
return;
|
|
38
28
|
}
|
|
29
|
+
cb(null, chunk);
|
|
39
30
|
},
|
|
40
31
|
});
|
|
41
32
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type AbortableSignal } from '@naturalcycles/js-lib';
|
|
1
2
|
import { ErrorMode } from '@naturalcycles/js-lib/error';
|
|
2
3
|
import type { CommonLogger } from '@naturalcycles/js-lib/log';
|
|
3
4
|
import { type AbortableAsyncMapper, type AsyncPredicate, END, type PositiveInteger, type Promisable, SKIP, type StringMap, type UnixTimestampMillis } from '@naturalcycles/js-lib/types';
|
|
@@ -57,6 +58,10 @@ export interface TransformMapOptions<IN = any, OUT = IN> {
|
|
|
57
58
|
*/
|
|
58
59
|
metric?: string;
|
|
59
60
|
logger?: CommonLogger;
|
|
61
|
+
/**
|
|
62
|
+
* Allows to abort (gracefully stop) the stream from inside the Transform.
|
|
63
|
+
*/
|
|
64
|
+
signal?: AbortableSignal;
|
|
60
65
|
}
|
|
61
66
|
export interface TransformMapStats {
|
|
62
67
|
/**
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { _hc } from '@naturalcycles/js-lib';
|
|
2
2
|
import { _since } from '@naturalcycles/js-lib/datetime/time.util.js';
|
|
3
|
-
import { _anyToError, ErrorMode } from '@naturalcycles/js-lib/error';
|
|
3
|
+
import { _anyToError, _assert, ErrorMode } from '@naturalcycles/js-lib/error';
|
|
4
4
|
import { _stringify } from '@naturalcycles/js-lib/string/stringify.js';
|
|
5
5
|
import { END, SKIP, } from '@naturalcycles/js-lib/types';
|
|
6
6
|
import through2Concurrent from 'through2-concurrent';
|
|
7
7
|
import { yellow } from '../../colors/colors.js';
|
|
8
|
-
import {
|
|
8
|
+
import { PIPELINE_GRACEFUL_ABORT } from '../stream.util.js';
|
|
9
9
|
// doesn't work, cause here we don't construct our Transform instance ourselves
|
|
10
10
|
// export class TransformMap extends AbortableTransform {}
|
|
11
11
|
/**
|
|
@@ -22,11 +22,12 @@ import { pipelineClose } from '../stream.util.js';
|
|
|
22
22
|
*/
|
|
23
23
|
export function transformMap(mapper, opt = {}) {
|
|
24
24
|
const { concurrency = 16, highWaterMark = 64, predicate, // we now default to "no predicate" (meaning pass-everything)
|
|
25
|
-
errorMode = ErrorMode.THROW_IMMEDIATELY, onError, onDone, metric = 'stream', logger = console, } = opt;
|
|
25
|
+
errorMode = ErrorMode.THROW_IMMEDIATELY, onError, onDone, metric = 'stream', logger = console, signal, } = opt;
|
|
26
26
|
const started = Date.now();
|
|
27
27
|
let index = -1;
|
|
28
28
|
let countOut = 0;
|
|
29
29
|
let isSettled = false;
|
|
30
|
+
let ok = true;
|
|
30
31
|
let errors = 0;
|
|
31
32
|
const collectedErrors = []; // only used if errorMode == THROW_AGGREGATED
|
|
32
33
|
return through2Concurrent.obj({
|
|
@@ -57,7 +58,7 @@ export function transformMap(mapper, opt = {}) {
|
|
|
57
58
|
// emit no error
|
|
58
59
|
try {
|
|
59
60
|
await onDone?.({
|
|
60
|
-
ok
|
|
61
|
+
ok,
|
|
61
62
|
collectedErrors,
|
|
62
63
|
countErrors: errors,
|
|
63
64
|
countIn: index + 1,
|
|
@@ -84,7 +85,8 @@ export function transformMap(mapper, opt = {}) {
|
|
|
84
85
|
if (res === END) {
|
|
85
86
|
isSettled = true;
|
|
86
87
|
logger.log(`transformMap END received at index ${currentIndex}`);
|
|
87
|
-
|
|
88
|
+
_assert(signal, 'signal is required when using END');
|
|
89
|
+
signal.abort(new Error(PIPELINE_GRACEFUL_ABORT));
|
|
88
90
|
return cb();
|
|
89
91
|
}
|
|
90
92
|
if (res === SKIP) {
|
|
@@ -110,19 +112,21 @@ export function transformMap(mapper, opt = {}) {
|
|
|
110
112
|
}
|
|
111
113
|
if (errorMode === ErrorMode.THROW_IMMEDIATELY) {
|
|
112
114
|
isSettled = true;
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
}
|
|
115
|
+
ok = false;
|
|
116
|
+
// Tests show that onDone is still called at `final` (second time),
|
|
117
|
+
// so, we no longer call it here
|
|
118
|
+
// try {
|
|
119
|
+
// await onDone?.({
|
|
120
|
+
// ok: false,
|
|
121
|
+
// collectedErrors,
|
|
122
|
+
// countErrors: errors,
|
|
123
|
+
// countIn: index + 1,
|
|
124
|
+
// countOut,
|
|
125
|
+
// started,
|
|
126
|
+
// })
|
|
127
|
+
// } catch (err) {
|
|
128
|
+
// logger.error(err)
|
|
129
|
+
// }
|
|
126
130
|
return cb(err); // Emit error immediately
|
|
127
131
|
}
|
|
128
132
|
if (errorMode === ErrorMode.THROW_AGGREGATED) {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import type { AbortableSignal } from '@naturalcycles/js-lib';
|
|
1
2
|
import { ErrorMode } from '@naturalcycles/js-lib/error';
|
|
2
3
|
import type { CommonLogger } from '@naturalcycles/js-lib/log';
|
|
3
4
|
import type { IndexedMapper, Predicate } from '@naturalcycles/js-lib/types';
|
|
4
5
|
import { END, SKIP } from '@naturalcycles/js-lib/types';
|
|
5
|
-
import { AbortableTransform } from '../pipeline/pipeline.js';
|
|
6
6
|
import type { TransformTyped } from '../stream.model.js';
|
|
7
7
|
import type { TransformMapStats } from './transformMap.js';
|
|
8
8
|
export interface TransformMapSyncOptions<IN = any, OUT = IN> {
|
|
@@ -45,8 +45,10 @@ export interface TransformMapSyncOptions<IN = any, OUT = IN> {
|
|
|
45
45
|
*/
|
|
46
46
|
metric?: string;
|
|
47
47
|
logger?: CommonLogger;
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
/**
|
|
49
|
+
* Allows to abort (gracefully stop) the stream from inside the Transform.
|
|
50
|
+
*/
|
|
51
|
+
signal?: AbortableSignal;
|
|
50
52
|
}
|
|
51
53
|
/**
|
|
52
54
|
* Sync (not async) version of transformMap.
|
|
@@ -1,24 +1,22 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Transform } from 'node:stream';
|
|
2
|
+
import { _anyToError, _assert, ErrorMode } from '@naturalcycles/js-lib/error';
|
|
2
3
|
import { END, SKIP } from '@naturalcycles/js-lib/types';
|
|
3
4
|
import { yellow } from '../../colors/colors.js';
|
|
4
|
-
import {
|
|
5
|
-
import { pipelineClose } from '../stream.util.js';
|
|
6
|
-
export class TransformMapSync extends AbortableTransform {
|
|
7
|
-
}
|
|
5
|
+
import { PIPELINE_GRACEFUL_ABORT } from '../stream.util.js';
|
|
8
6
|
/**
|
|
9
7
|
* Sync (not async) version of transformMap.
|
|
10
8
|
* Supposedly faster, for cases when async is not needed.
|
|
11
9
|
*/
|
|
12
10
|
export function transformMapSync(mapper, opt = {}) {
|
|
13
11
|
const { predicate, // defaults to "no predicate" (pass everything)
|
|
14
|
-
errorMode = ErrorMode.THROW_IMMEDIATELY, onError, onDone, metric = 'stream', objectMode = true, logger = console, } = opt;
|
|
12
|
+
errorMode = ErrorMode.THROW_IMMEDIATELY, onError, onDone, metric = 'stream', objectMode = true, logger = console, signal, } = opt;
|
|
15
13
|
const started = Date.now();
|
|
16
14
|
let index = -1;
|
|
17
15
|
let countOut = 0;
|
|
18
16
|
let isSettled = false;
|
|
19
17
|
let errors = 0;
|
|
20
18
|
const collectedErrors = []; // only used if errorMode == THROW_AGGREGATED
|
|
21
|
-
return new
|
|
19
|
+
return new Transform({
|
|
22
20
|
objectMode,
|
|
23
21
|
...opt,
|
|
24
22
|
transform(chunk, _, cb) {
|
|
@@ -32,7 +30,8 @@ export function transformMapSync(mapper, opt = {}) {
|
|
|
32
30
|
if (v === END) {
|
|
33
31
|
isSettled = true; // will be checked later
|
|
34
32
|
logger.log(`transformMapSync END received at index ${currentIndex}`);
|
|
35
|
-
|
|
33
|
+
_assert(signal, 'signal is required when using END');
|
|
34
|
+
signal.abort(new Error(PIPELINE_GRACEFUL_ABORT));
|
|
36
35
|
return cb();
|
|
37
36
|
}
|
|
38
37
|
if (v === SKIP) {
|
|
@@ -11,8 +11,9 @@ import { Transform } from 'node:stream';
|
|
|
11
11
|
export function transformSplitOnNewline() {
|
|
12
12
|
let buffered;
|
|
13
13
|
return new Transform({
|
|
14
|
-
|
|
14
|
+
writableObjectMode: false,
|
|
15
15
|
writableHighWaterMark: 64 * 1024,
|
|
16
|
+
readableObjectMode: true,
|
|
16
17
|
transform(buf, _enc, done) {
|
|
17
18
|
let offset = 0;
|
|
18
19
|
let lastMatch = 0;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Transform } from 'node:stream';
|
|
2
|
-
import {
|
|
2
|
+
import { pipeline } from 'node:stream/promises';
|
|
3
3
|
import { readableCreate } from '../readable/readableCreate.js';
|
|
4
4
|
/**
|
|
5
5
|
* Allows to "tee"/"fork" away from the "main pipeline" into the "secondary pipeline".
|
|
@@ -12,10 +12,12 @@ import { readableCreate } from '../readable/readableCreate.js';
|
|
|
12
12
|
*/
|
|
13
13
|
export function transformTee(streams) {
|
|
14
14
|
const readable = readableCreate();
|
|
15
|
-
const secondPipelinePromise =
|
|
15
|
+
const secondPipelinePromise = pipeline([readable, ...streams]);
|
|
16
16
|
return new Transform({
|
|
17
17
|
objectMode: true,
|
|
18
18
|
transform(chunk, _, cb) {
|
|
19
|
+
// todo: it's possible to start respecting backpressure,
|
|
20
|
+
// if we start to listen to the boolean output of .push()
|
|
19
21
|
// pass to the "secondary" pipeline
|
|
20
22
|
readable.push(chunk);
|
|
21
23
|
// pass through to the "main" pipeline
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { AsyncIndexedMapper, IndexedMapper } from '@naturalcycles/js-lib/types';
|
|
2
2
|
import type { WritableTyped } from '../stream.model.js';
|
|
3
3
|
import { type TransformMapOptions } from '../transform/transformMap.js';
|
|
4
|
+
import { type TransformMapSyncOptions } from '../transform/transformMapSync.js';
|
|
4
5
|
/**
|
|
5
6
|
* Just an alias to transformMap that declares OUT as void.
|
|
6
7
|
*/
|
|
@@ -8,4 +9,4 @@ export declare function writableForEach<IN = any>(mapper: AsyncIndexedMapper<IN,
|
|
|
8
9
|
/**
|
|
9
10
|
* Just an alias to transformMap that declares OUT as void.
|
|
10
11
|
*/
|
|
11
|
-
export declare function writableForEachSync<IN = any>(mapper: IndexedMapper<IN, void>, opt?:
|
|
12
|
+
export declare function writableForEachSync<IN = any>(mapper: IndexedMapper<IN, void>, opt?: TransformMapSyncOptions<IN, void>): WritableTyped<IN>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Writable } from 'node:stream';
|
|
2
|
-
import {
|
|
2
|
+
import { pipeline } from 'node:stream/promises';
|
|
3
3
|
import { readableCreate } from '../readable/readableCreate.js';
|
|
4
4
|
/**
|
|
5
5
|
* Allows "forking" a stream inside pipeline into a number of pipeline chains (2 or more).
|
|
@@ -14,7 +14,7 @@ export function writableFork(chains, opt) {
|
|
|
14
14
|
const allChainsDone = Promise.all(chains.map(async (chain) => {
|
|
15
15
|
const readable = readableCreate();
|
|
16
16
|
readables.push(readable);
|
|
17
|
-
return await
|
|
17
|
+
return await pipeline([readable, ...chain]);
|
|
18
18
|
})).catch(err => {
|
|
19
19
|
console.error(err); // ensure the error is logged
|
|
20
20
|
throw err;
|
package/package.json
CHANGED
package/src/exec2/exec2.ts
CHANGED
package/src/stream/index.ts
CHANGED
|
@@ -5,11 +5,10 @@ export * from './ndjson/ndjsonMap.js'
|
|
|
5
5
|
export * from './ndjson/ndjsonStreamForEach.js'
|
|
6
6
|
export * from './ndjson/transformJsonParse.js'
|
|
7
7
|
export * from './ndjson/transformToNDJson.js'
|
|
8
|
-
export * from './pipeline
|
|
8
|
+
export * from './pipeline.js'
|
|
9
9
|
export * from './progressLogger.js'
|
|
10
10
|
export * from './readable/readableCombined.js'
|
|
11
11
|
export * from './readable/readableCreate.js'
|
|
12
|
-
export * from './readable/readableForEach.js'
|
|
13
12
|
export * from './readable/readableFromArray.js'
|
|
14
13
|
export * from './readable/readableToArray.js'
|
|
15
14
|
export * from './stream.model.js'
|
|
@@ -1,13 +1,7 @@
|
|
|
1
1
|
import { ErrorMode } from '@naturalcycles/js-lib/error/errorMode.js'
|
|
2
2
|
import type { AbortableAsyncMapper } from '@naturalcycles/js-lib/types'
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
createWriteStreamAsNDJSON,
|
|
6
|
-
transformFlatten,
|
|
7
|
-
type TransformLogProgressOptions,
|
|
8
|
-
type TransformMapOptions,
|
|
9
|
-
} from '../index.js'
|
|
10
|
-
import { _pipeline, transformLimit, transformLogProgress, transformMap } from '../index.js'
|
|
3
|
+
import type { TransformLogProgressOptions, TransformMapOptions } from '../index.js'
|
|
4
|
+
import { Pipeline } from '../pipeline.js'
|
|
11
5
|
|
|
12
6
|
export interface NDJSONMapOptions<IN = any, OUT = IN>
|
|
13
7
|
extends TransformMapOptions<IN, OUT>,
|
|
@@ -39,20 +33,16 @@ export async function ndjsonMap<IN = any, OUT = any>(
|
|
|
39
33
|
outputFilePath,
|
|
40
34
|
})
|
|
41
35
|
|
|
42
|
-
|
|
43
|
-
limitInput
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
await _pipeline([
|
|
47
|
-
readable,
|
|
48
|
-
transformLogProgress({ metric: 'read', ...opt }),
|
|
49
|
-
transformMap(mapper, {
|
|
36
|
+
await Pipeline.fromNDJsonFile<IN>(inputFilePath)
|
|
37
|
+
.limitSource(limitInput)
|
|
38
|
+
.logProgress({ metric: 'read', ...opt })
|
|
39
|
+
.map(mapper, {
|
|
50
40
|
errorMode: ErrorMode.SUPPRESS,
|
|
51
41
|
...opt,
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
42
|
+
})
|
|
43
|
+
.flattenIfNeeded()
|
|
44
|
+
// .typeCastAs<OUT>()
|
|
45
|
+
.limit(limitOutput)
|
|
46
|
+
.logProgress({ metric: 'saved', logEvery: logEveryOutput })
|
|
47
|
+
.toNDJsonFile(outputFilePath)
|
|
58
48
|
}
|
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
import { ErrorMode } from '@naturalcycles/js-lib/error/errorMode.js'
|
|
2
2
|
import type { AbortableAsyncMapper } from '@naturalcycles/js-lib/types'
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
type TransformLogProgressOptions,
|
|
7
|
-
} from '../transform/transformLogProgress.js'
|
|
8
|
-
import { transformMap, type TransformMapOptions } from '../transform/transformMap.js'
|
|
9
|
-
import { writableVoid } from '../writable/writableVoid.js'
|
|
10
|
-
import { createReadStreamAsNDJSON } from './createReadStreamAsNDJSON.js'
|
|
3
|
+
import { Pipeline } from '../pipeline.js'
|
|
4
|
+
import type { TransformLogProgressOptions } from '../transform/transformLogProgress.js'
|
|
5
|
+
import type { TransformMapOptions } from '../transform/transformMap.js'
|
|
11
6
|
|
|
12
7
|
export interface NDJSONStreamForEachOptions<IN = any>
|
|
13
8
|
extends TransformMapOptions<IN, void>,
|
|
@@ -22,14 +17,12 @@ export async function ndjsonStreamForEach<T>(
|
|
|
22
17
|
mapper: AbortableAsyncMapper<T, void>,
|
|
23
18
|
opt: NDJSONStreamForEachOptions<T>,
|
|
24
19
|
): Promise<void> {
|
|
25
|
-
await
|
|
26
|
-
|
|
27
|
-
transformMap<T, any>(mapper, {
|
|
20
|
+
await Pipeline.fromNDJsonFile<T>(opt.inputFilePath)
|
|
21
|
+
.map(mapper, {
|
|
28
22
|
errorMode: ErrorMode.THROW_AGGREGATED,
|
|
29
23
|
...opt,
|
|
30
24
|
predicate: () => true, // to log progress properly
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
])
|
|
25
|
+
})
|
|
26
|
+
.logProgress(opt)
|
|
27
|
+
.run()
|
|
35
28
|
}
|