| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2007,7 +2007,7 @@ changes: | |||
| 2007 | 2007 | description: Marking the API stable. | |
| 2008 | 2008 | --> | |
| 2009 | 2009 | ||
| 2010 | - * `stream` {Stream|Iterable|AsyncIterable|Function} | ||
| 2010 | + * `stream` {Writable|Duplex|WritableStream|TransformStream|Function} | ||
| 2011 | 2011 | * `options` {Object} | |
| 2012 | 2012 | * `signal` {AbortSignal} allows destroying the stream if the signal is | |
| 2013 | 2013 | aborted. | |
@@ -2026,13 +2026,18 @@ async function* splitToWords(source) { | |||
| 2026 | 2026 | } | |
| 2027 | 2027 | } | |
| 2028 | 2028 | ||
| 2029 | - const wordsStream = Readable.from(['this is', 'compose as operator']).compose(splitToWords); | ||
| 2029 | + const wordsStream = Readable.from(['text passed through', 'composed stream']).compose(splitToWords); | ||
| 2030 | 2030 | const words = await wordsStream.toArray(); | |
| 2031 | 2031 | ||
| 2032 | - console.log(words); // prints ['this', 'is', 'compose', 'as', 'operator'] | ||
| 2032 | + console.log(words); // prints ['text', 'passed', 'through', 'composed', 'stream'] | ||
| 2033 | 2033 | ``` | |
| 2034 | 2034 | ||
| 2035 | - See [`stream.compose`][] for more information. | ||
| 2035 | + `readable.compose(s)` is equivalent to `stream.compose(readable, s)`. | ||
| 2036 | + | ||
| 2037 | + This method also allows for an {AbortSignal} to be provided, which will destroy | ||
| 2038 | + the composed stream when aborted. | ||
| 2039 | + | ||
| 2040 | + See [`stream.compose(...streams)`][] for more information. | ||
| 2036 | 2041 | ||
| 2037 | 2042 | ##### `readable.iterator([options])` | |
| 2038 | 2043 | ||
@@ -3026,7 +3031,8 @@ await finished(compose(s1, s2, s3)); | |||
| 3026 | 3031 | console.log(res); // prints 'HELLOWORLD' | |
| 3027 | 3032 | ``` | |
| 3028 | 3033 | ||
| 3029 | - See [`readable.compose(stream)`][] for `stream.compose` as operator. | ||
| 3034 | + For convenience, the [`readable.compose(stream)`][] method is available on | ||
| 3035 | + {Readable} and {Duplex} streams as a wrapper for this function. | ||
| 3030 | 3036 | ||
| 3031 | 3037 | ### `stream.isErrored(stream)` | |
| 3032 | 3038 | ||
@@ -4945,7 +4951,7 @@ contain multi-byte characters. | |||
| 4945 | 4951 | [`readable.setEncoding()`]: #readablesetencodingencoding | |
| 4946 | 4952 | [`stream.Readable.from()`]: #streamreadablefromiterable-options | |
| 4947 | 4953 | [`stream.addAbortSignal()`]: #streamaddabortsignalsignal-stream | |
| 4948 | - [`stream.compose`]: #streamcomposestreams | ||
| 4954 | + [`stream.compose(...streams)`]: #streamcomposestreams | ||
| 4949 | 4955 | [`stream.cork()`]: #writablecork | |
| 4950 | 4956 | [`stream.duplexPair()`]: #streamduplexpairoptions | |
| 4951 | 4957 | [`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 | |
|---|---|---|---|
@@ -49,6 +49,7 @@ const { | |||
| 49 | 49 | ||
| 50 | 50 | const { | |
| 51 | 51 | addAbortSignal, | |
| 52 | + addAbortSignalNoValidate, | ||
| 52 | 53 | } = require('internal/streams/add-abort-signal'); | |
| 53 | 54 | const eos = require('internal/streams/end-of-stream'); | |
| 54 | 55 | ||
@@ -87,7 +88,10 @@ const { | |||
| 87 | 88 | ERR_UNKNOWN_ENCODING, | |
| 88 | 89 | }, | |
| 89 | 90 | } = require('internal/errors'); | |
| 90 | - const { validateObject } = require('internal/validators'); | ||
| 91 | + const { | ||
| 92 | + validateAbortSignal, | ||
| 93 | + validateObject, | ||
| 94 | + } = require('internal/validators'); | ||
| 91 | 95 | ||
| 92 | 96 | const FastBuffer = Buffer[SymbolSpecies]; | |
| 93 | 97 | ||
@@ -1406,6 +1410,30 @@ async function* createAsyncIterator(stream, options) { | |||
| 1406 | 1410 | } | |
| 1407 | 1411 | } | |
| 1408 | 1412 | ||
| 1413 | + let composeImpl; | ||
| 1414 | + | ||
| 1415 | + Readable.prototype.compose = function compose(stream, options) { | ||
| 1416 | + if (options != null) { | ||
| 1417 | + validateObject(options, 'options'); | ||
| 1418 | + } | ||
| 1419 | + if (options?.signal != null) { | ||
| 1420 | + validateAbortSignal(options.signal, 'options.signal'); | ||
| 1421 | + } | ||
| 1422 | + | ||
| 1423 | + composeImpl ??= require('internal/streams/compose'); | ||
| 1424 | + const composedStream = composeImpl(this, stream); | ||
| 1425 | + | ||
| 1426 | + if (options?.signal) { | ||
| 1427 | + // Not validating as we already validated before | ||
| 1428 | + addAbortSignalNoValidate( | ||
| 1429 | + options.signal, | ||
| 1430 | + composedStream, | ||
| 1431 | + ); | ||
| 1432 | + } | ||
| 1433 | + | ||
| 1434 | + return composedStream; | ||
| 1435 | + }; | ||
| 1436 | + | ||
| 1409 | 1437 | // Making it explicit these properties are not enumerable | |
| 1410 | 1438 | // because otherwise some prototype manipulation in | |
| 1411 | 1439 | // 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