@naturalcycles/nodejs-lib 15.22.0 → 15.23.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 +79 -0
- package/dist/stream/pipeline.js +220 -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/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 +301 -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/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,114 +0,0 @@
|
|
|
1
|
-
import type { Readable, Writable } from 'node:stream'
|
|
2
|
-
import { Transform } from 'node:stream'
|
|
3
|
-
import { pipeline } from 'node:stream/promises'
|
|
4
|
-
import { _last } from '@naturalcycles/js-lib/array/array.util.js'
|
|
5
|
-
import type { DeferredPromise } from '@naturalcycles/js-lib/promise'
|
|
6
|
-
import { pDefer } from '@naturalcycles/js-lib/promise/pDefer.js'
|
|
7
|
-
import type { AnyFunction } from '@naturalcycles/js-lib/types'
|
|
8
|
-
import { writablePushToArray } from '../writable/writablePushToArray.js'
|
|
9
|
-
|
|
10
|
-
type AnyStream = NodeJS.ReadableStream | NodeJS.WritableStream | NodeJS.ReadWriteStream
|
|
11
|
-
|
|
12
|
-
export interface PipelineOptions {
|
|
13
|
-
/**
|
|
14
|
-
* Set to true to allow ERR_STREAM_PREMATURE_CLOSE.
|
|
15
|
-
* Required to support graceful close when using transformLimit
|
|
16
|
-
*/
|
|
17
|
-
allowClose?: boolean
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Set to true to allow graceful abort (via AbortSignal).
|
|
21
|
-
* "Graceful" means it'll swallow the AbortError and let the pipeline resolve normally.
|
|
22
|
-
*
|
|
23
|
-
* Default is false - AbortError will be thrown.
|
|
24
|
-
*/
|
|
25
|
-
allowGracefulAbort?: boolean
|
|
26
|
-
|
|
27
|
-
signal?: AbortSignal
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Promisified `stream.pipeline`.
|
|
32
|
-
*
|
|
33
|
-
* Supports opt.allowClose, which allows transformLimit to work (to actually stop source Readable)
|
|
34
|
-
* without throwing an error (ERR_STREAM_PREMATURE_CLOSE).
|
|
35
|
-
*/
|
|
36
|
-
export async function _pipeline(streams: AnyStream[], opt: PipelineOptions = {}): Promise<void> {
|
|
37
|
-
const first = streams[0] as any
|
|
38
|
-
const rest = streams.slice(1)
|
|
39
|
-
|
|
40
|
-
if (opt.allowClose) {
|
|
41
|
-
// Do the magic of making the pipeline "abortable"
|
|
42
|
-
//
|
|
43
|
-
// How does it work:
|
|
44
|
-
// It finds `sourceReadable` (basically, it's just first item in the passed array of streams)
|
|
45
|
-
// Finds last "writable" (last item), patches the `_final` method of it to detect when the whole pipeline is "done",
|
|
46
|
-
// sets the `streamDone` DeferredPromise that resolves when the pipeline is done.
|
|
47
|
-
// Scans through all passed items, finds those that are capable of "closing" the stream
|
|
48
|
-
// (currently its `transformLimit` or `transformMap`)
|
|
49
|
-
// Patches them by attaching `sourceReadable` and `streamDone`.
|
|
50
|
-
// These items (transformLimit and transformMap), when they need to "close the stream" - call `pipelineClose`.
|
|
51
|
-
// `pipelineClose` is the result of 2 sleepless nights of googling and experimentation:)
|
|
52
|
-
// It does:
|
|
53
|
-
// 1. Stops the "downstream" by doing `this.push(null)`.
|
|
54
|
-
// 2. Pauses the `sourceReadable` by calling sourceReadable.unpipe()
|
|
55
|
-
// 3. Waits for `streamDone` to ensure that downstream chunks are fully processed (e.g written to disk).
|
|
56
|
-
// 4. Calls `sourceReadable.destroy()`, which emits ERR_STREAM_PREMATURE_CLOSE
|
|
57
|
-
// 5. _pipeline (this function) catches that specific error and suppresses it (because it's expected and
|
|
58
|
-
// inevitable in this flow). Know a better way to close the stream? Tell me!
|
|
59
|
-
const streamDone = pDefer()
|
|
60
|
-
const sourceReadable = first as Readable
|
|
61
|
-
const last = _last(streams) as Writable
|
|
62
|
-
const lastFinal = last._final?.bind(last) || ((cb: AnyFunction) => cb())
|
|
63
|
-
last._final = cb => {
|
|
64
|
-
lastFinal(() => {
|
|
65
|
-
cb()
|
|
66
|
-
streamDone.resolve()
|
|
67
|
-
})
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
rest.forEach(s => {
|
|
71
|
-
// console.log(s)
|
|
72
|
-
if (s instanceof AbortableTransform || s.constructor.name === 'AbortableTransform') {
|
|
73
|
-
// console.log(`found ${s.constructor.name}, setting props`)
|
|
74
|
-
;(s as AbortableTransform).sourceReadable = sourceReadable
|
|
75
|
-
;(s as AbortableTransform).streamDone = streamDone
|
|
76
|
-
}
|
|
77
|
-
})
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
try {
|
|
81
|
-
return await pipeline([first, ...rest], opt)
|
|
82
|
-
} catch (err) {
|
|
83
|
-
if (opt.allowClose && (err as any)?.code === 'ERR_STREAM_PREMATURE_CLOSE') {
|
|
84
|
-
console.log('_pipeline closed (as expected)')
|
|
85
|
-
return
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (opt.allowGracefulAbort && (err as any)?.name === 'AbortError') {
|
|
89
|
-
console.log('_pipeline closed via AbortSignal (as expected)')
|
|
90
|
-
return
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// console.log(`_pipeline error`, err)
|
|
94
|
-
throw err
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Convenience function to make _pipeline collect all items at the end of the stream (should be Transform, not Writeable!)
|
|
100
|
-
* and return.
|
|
101
|
-
*/
|
|
102
|
-
export async function _pipelineToArray<T>(
|
|
103
|
-
streams: AnyStream[],
|
|
104
|
-
opt: PipelineOptions = {},
|
|
105
|
-
): Promise<T[]> {
|
|
106
|
-
const a: T[] = []
|
|
107
|
-
await _pipeline([...streams, writablePushToArray(a)], opt)
|
|
108
|
-
return a
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
export class AbortableTransform extends Transform {
|
|
112
|
-
sourceReadable?: Readable
|
|
113
|
-
streamDone?: DeferredPromise
|
|
114
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import type { AbortableAsyncMapper, IndexedMapper } from '@naturalcycles/js-lib/types'
|
|
2
|
-
import { _passNothingPredicate } from '@naturalcycles/js-lib/types'
|
|
3
|
-
import { _pipeline } from '../pipeline/pipeline.js'
|
|
4
|
-
import type { ReadableTyped } from '../stream.model.js'
|
|
5
|
-
import type { TransformMapOptions } from '../transform/transformMap.js'
|
|
6
|
-
import { transformMap } from '../transform/transformMap.js'
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Convenience function to do `.forEach` over a Readable.
|
|
10
|
-
* Typed! (unlike default Readable).
|
|
11
|
-
*
|
|
12
|
-
* Try native readable.forEach() instead!
|
|
13
|
-
*
|
|
14
|
-
* @experimental
|
|
15
|
-
*/
|
|
16
|
-
export async function readableForEach<T>(
|
|
17
|
-
readable: ReadableTyped<T>,
|
|
18
|
-
mapper: AbortableAsyncMapper<T, void>,
|
|
19
|
-
opt: TransformMapOptions<T, void> = {},
|
|
20
|
-
): Promise<void> {
|
|
21
|
-
await _pipeline([
|
|
22
|
-
readable,
|
|
23
|
-
transformMap<T, void>(mapper, { ...opt, predicate: _passNothingPredicate }),
|
|
24
|
-
])
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Convenience function to do `.forEach` over a Readable.
|
|
29
|
-
* Typed! (unlike default Readable).
|
|
30
|
-
*
|
|
31
|
-
* @experimental
|
|
32
|
-
*/
|
|
33
|
-
export async function readableForEachSync<T>(
|
|
34
|
-
readable: ReadableTyped<T>,
|
|
35
|
-
mapper: IndexedMapper<T, void>,
|
|
36
|
-
): Promise<void> {
|
|
37
|
-
// async iteration
|
|
38
|
-
let index = 0
|
|
39
|
-
for await (const item of readable) {
|
|
40
|
-
mapper(item, index++)
|
|
41
|
-
}
|
|
42
|
-
}
|