| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2027,7 +2027,7 @@ changes: | |||
| 2027 | 2027 | description: Marking the API stable. | |
| 2028 | 2028 | --> | |
| 2029 | 2029 | ||
| 2030 | - * `stream` {Stream|Iterable|AsyncIterable|Function} | ||
| 2030 | + * `stream` {Writable|Duplex|WritableStream|TransformStream|Function} | ||
| 2031 | 2031 | * `options` {Object} | |
| 2032 | 2032 | * `signal` {AbortSignal} allows destroying the stream if the signal is | |
| 2033 | 2033 | aborted. | |
@@ -2046,13 +2046,18 @@ async function* splitToWords(source) { | |||
| 2046 | 2046 | } | |
| 2047 | 2047 | } | |
| 2048 | 2048 | ||
| 2049 | - const wordsStream = Readable.from(['this is', 'compose as operator']).compose(splitToWords); | ||
| 2049 | + const wordsStream = Readable.from(['text passed through', 'composed stream']).compose(splitToWords); | ||
| 2050 | 2050 | const words = await wordsStream.toArray(); | |
| 2051 | 2051 | ||
| 2052 | - console.log(words); // prints ['this', 'is', 'compose', 'as', 'operator'] | ||
| 2052 | + console.log(words); // prints ['text', 'passed', 'through', 'composed', 'stream'] | ||
| 2053 | 2053 | ``` | |
| 2054 | 2054 | ||
| 2055 | - See [`stream.compose`][] for more information. | ||
| 2055 | + `readable.compose(s)` is equivalent to `stream.compose(readable, s)`. | ||
| 2056 | + | ||
| 2057 | + This method also allows for an {AbortSignal} to be provided, which will destroy | ||
| 2058 | + the composed stream when aborted. | ||
| 2059 | + | ||
| 2060 | + See [`stream.compose(...streams)`][] for more information. | ||
| 2056 | 2061 | ||
| 2057 | 2062 | ##### `readable.iterator([options])` | |
| 2058 | 2063 | ||
@@ -3050,7 +3055,8 @@ await finished(compose(s1, s2, s3)); | |||
| 3050 | 3055 | console.log(res); // prints 'HELLOWORLD' | |
| 3051 | 3056 | ``` | |
| 3052 | 3057 | ||
| 3053 | - See [`readable.compose(stream)`][] for `stream.compose` as operator. | ||
| 3058 | + For convenience, the [`readable.compose(stream)`][] method is available on | ||
| 3059 | + {Readable} and {Duplex} streams as a wrapper for this function. | ||
| 3054 | 3060 | ||
| 3055 | 3061 | ### `stream.isErrored(stream)` | |
| 3056 | 3062 | ||
@@ -4998,7 +5004,7 @@ contain multi-byte characters. | |||
| 4998 | 5004 | [`readable.setEncoding()`]: #readablesetencodingencoding | |
| 4999 | 5005 | [`stream.Readable.from()`]: #streamreadablefromiterable-options | |
| 5000 | 5006 | [`stream.addAbortSignal()`]: #streamaddabortsignalsignal-stream | |
| 5001 | - [`stream.compose`]: #streamcomposestreams | ||
| 5007 | + [`stream.compose(...streams)`]: #streamcomposestreams | ||
| 5002 | 5008 | [`stream.cork()`]: #writablecork | |
| 5003 | 5009 | [`stream.duplexPair()`]: #streamduplexpairoptions | |
| 5004 | 5010 | [`stream.finished()`]: #streamfinishedstream-options-callback | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -18,7 +18,6 @@ const { AbortController, AbortSignal } = require('internal/abort_controller'); | |||
| 18 | 18 | const { | |
| 19 | 19 | AbortError, | |
| 20 | 20 | codes: { | |
| 21 | - ERR_INVALID_ARG_VALUE, | ||
| 22 | 21 | ERR_MISSING_ARGS, | |
| 23 | 22 | ERR_OUT_OF_RANGE, | |
| 24 | 23 | }, | |
@@ -31,40 +30,10 @@ const { | |||
| 31 | 30 | } = require('internal/validators'); | |
| 32 | 31 | const { kWeakHandler, kResistStopPropagation } = require('internal/event_target'); | |
| 33 | 32 | const { finished } = require('internal/streams/end-of-stream'); | |
| 34 | - const staticCompose = require('internal/streams/compose'); | ||
| 35 | - const { | ||
| 36 | - addAbortSignalNoValidate, | ||
| 37 | - } = require('internal/streams/add-abort-signal'); | ||
| 38 | - const { isWritable, isNodeStream } = require('internal/streams/utils'); | ||
| 39 | 33 | ||
| 40 | 34 | const kEmpty = Symbol('kEmpty'); | |
| 41 | 35 | const kEof = Symbol('kEof'); | |
| 42 | 36 | ||
| 43 | - function compose(stream, options) { | ||
| 44 | - if (options != null) { | ||
| 45 | - validateObject(options, 'options'); | ||
| 46 | - } | ||
| 47 | - if (options?.signal != null) { | ||
| 48 | - validateAbortSignal(options.signal, 'options.signal'); | ||
| 49 | - } | ||
| 50 | - | ||
| 51 | - if (isNodeStream(stream) && !isWritable(stream)) { | ||
| 52 | - throw new ERR_INVALID_ARG_VALUE('stream', stream, 'must be writable'); | ||
| 53 | - } | ||
| 54 | - | ||
| 55 | - const composedStream = staticCompose(this, stream); | ||
| 56 | - | ||
| 57 | - if (options?.signal) { | ||
| 58 | - // Not validating as we already validated before | ||
| 59 | - addAbortSignalNoValidate( | ||
| 60 | - options.signal, | ||
| 61 | - composedStream, | ||
| 62 | - ); | ||
| 63 | - } | ||
| 64 | - | ||
| 65 | - return composedStream; | ||
| 66 | - } | ||
| 67 | - | ||
| 68 | 37 | function map(fn, options) { | |
| 69 | 38 | validateFunction(fn, 'fn'); | |
| 70 | 39 | if (options != null) { | |
@@ -408,7 +377,6 @@ module.exports.streamReturningOperators = { | |||
| 408 | 377 | flatMap, | |
| 409 | 378 | map, | |
| 410 | 379 | take, | |
| 411 | - compose, | ||
| 412 | 380 | }; | |
| 413 | 381 | ||
| 414 | 382 | module.exports.promiseReturningOperators = { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -48,6 +48,7 @@ const { Buffer } = require('buffer'); | |||
| 48 | 48 | ||
| 49 | 49 | const { | |
| 50 | 50 | addAbortSignal, | |
| 51 | + addAbortSignalNoValidate, | ||
| 51 | 52 | } = require('internal/streams/add-abort-signal'); | |
| 52 | 53 | const eos = require('internal/streams/end-of-stream'); | |
| 53 | 54 | ||
@@ -86,7 +87,10 @@ const { | |||
| 86 | 87 | ERR_UNKNOWN_ENCODING, | |
| 87 | 88 | }, | |
| 88 | 89 | } = require('internal/errors'); | |
| 89 | - const { validateObject } = require('internal/validators'); | ||
| 90 | + const { | ||
| 91 | + validateAbortSignal, | ||
| 92 | + validateObject, | ||
| 93 | + } = require('internal/validators'); | ||
| 90 | 94 | ||
| 91 | 95 | const FastBuffer = Buffer[SymbolSpecies]; | |
| 92 | 96 | ||
@@ -1409,6 +1413,30 @@ async function* createAsyncIterator(stream, options) { | |||
| 1409 | 1413 | } | |
| 1410 | 1414 | } | |
| 1411 | 1415 | ||
| 1416 | + let composeImpl; | ||
| 1417 | + | ||
| 1418 | + Readable.prototype.compose = function compose(stream, options) { | ||
| 1419 | + if (options != null) { | ||
| 1420 | + validateObject(options, 'options'); | ||
| 1421 | + } | ||
| 1422 | + if (options?.signal != null) { | ||
| 1423 | + validateAbortSignal(options.signal, 'options.signal'); | ||
| 1424 | + } | ||
| 1425 | + | ||
| 1426 | + composeImpl ??= require('internal/streams/compose'); | ||
| 1427 | + const composedStream = composeImpl(this, stream); | ||
| 1428 | + | ||
| 1429 | + if (options?.signal) { | ||
| 1430 | + // Not validating as we already validated before | ||
| 1431 | + addAbortSignalNoValidate( | ||
| 1432 | + options.signal, | ||
| 1433 | + composedStream, | ||
| 1434 | + ); | ||
| 1435 | + } | ||
| 1436 | + | ||
| 1437 | + return composedStream; | ||
| 1438 | + }; | ||
| 1439 | + | ||
| 1412 | 1440 | // Making it explicit these properties are not enumerable | |
| 1413 | 1441 | // because otherwise some prototype manipulation in | |
| 1414 | 1442 | // userland will fail. | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2,7 +2,9 @@ | |||
| 2 | 2 | ||
| 3 | 3 | const common = require('../common'); | |
| 4 | 4 | const { | |
| 5 | - Readable, Transform, | ||
| 5 | + PassThrough, | ||
| 6 | + Readable, | ||
| 7 | + Transform, | ||
| 6 | 8 | } = require('stream'); | |
| 7 | 9 | const assert = require('assert'); | |
| 8 | 10 | ||
@@ -19,6 +21,8 @@ const assert = require('assert'); | |||
| 19 | 21 | } | |
| 20 | 22 | } | |
| 21 | 23 | }); | |
| 24 | + assert.strictEqual(stream.readable, true); | ||
| 25 | + assert.strictEqual(stream.writable, false); | ||
| 22 | 26 | const result = ['ab', 'cd']; | |
| 23 | 27 | (async () => { | |
| 24 | 28 | for await (const item of stream) { | |
@@ -35,6 +39,8 @@ const assert = require('assert'); | |||
| 35 | 39 | callback(null, chunk); | |
| 36 | 40 | }, 4) | |
| 37 | 41 | })); | |
| 42 | + assert.strictEqual(stream.readable, true); | ||
| 43 | + assert.strictEqual(stream.writable, false); | ||
| 38 | 44 | const result = ['a', 'b', 'c', 'd']; | |
| 39 | 45 | (async () => { | |
| 40 | 46 | for await (const item of stream) { | |
@@ -43,6 +49,26 @@ const assert = require('assert'); | |||
| 43 | 49 | })().then(common.mustCall()); | |
| 44 | 50 | } | |
| 45 | 51 | ||
| 52 | + { | ||
| 53 | + // With Duplex stream as `this`, ensuring writes to the composed stream | ||
| 54 | + // are passed to the head of the pipeline | ||
| 55 | + const pt = new PassThrough({ objectMode: true }); | ||
| 56 | + const composed = pt.compose(async function *(stream) { | ||
| 57 | + for await (const chunk of stream) { | ||
| 58 | + yield chunk * 2; | ||
| 59 | + } | ||
| 60 | + }); | ||
| 61 | + assert.strictEqual(composed.readable, true); | ||
| 62 | + assert.strictEqual(composed.writable, true); | ||
| 63 | + pt.on('data', common.mustCall((chunk) => { | ||
| 64 | + assert.strictEqual(chunk, 123); | ||
| 65 | + })); | ||
| 66 | + composed.on('data', common.mustCall((chunk) => { | ||
| 67 | + assert.strictEqual(chunk, 246); | ||
| 68 | + })); | ||
| 69 | + composed.end(123); | ||
| 70 | + } | ||
| 71 | + | ||
| 46 | 72 | { | |
| 47 | 73 | // Throwing an error during `compose` (before waiting for data) | |
| 48 | 74 | const stream = Readable.from([1, 2, 3, 4, 5]).compose(async function *(stream) { // eslint-disable-line require-yield | |
| Back | FazBrowse Home | New Git URL |
0 commit comments