├── test ├── .gitkeep └── index.js ├── .eslintignore ├── .gitattributes ├── .npmrc ├── .eslintrc ├── .prettierignore ├── .editorconfig ├── .github └── workflows │ ├── release.yml │ └── dev.yml ├── CHANGELOG.md ├── LICENSE ├── package.json ├── .gitignore ├── README.md └── index.js /test/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | coverage/ 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text eol=lf 2 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "gulp" 3 | } 4 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | coverage/ 2 | .nyc_output/ 3 | CHANGELOG.md 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | end_of_line = lf 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: release 2 | on: 3 | push: 4 | branches: 5 | - master 6 | - main 7 | 8 | jobs: 9 | release-please: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: GoogleCloudPlatform/release-please-action@v2 13 | with: 14 | token: ${{ secrets.GITHUB_TOKEN }} 15 | release-type: node 16 | package-name: release-please-action 17 | bump-minor-pre-major: true 18 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [3.0.0](https://www.github.com/gulpjs/to-through/compare/v2.0.0...v3.0.0) (2022-09-07) 4 | 5 | 6 | ### ⚠ BREAKING CHANGES 7 | 8 | * Switch to streamx (#9) 9 | * Upgrade scaffold, dropping node <10 support (#8) 10 | 11 | ### Features 12 | 13 | * Switch to streamx ([#9](https://www.github.com/gulpjs/to-through/issues/9)) ([cf656cf](https://www.github.com/gulpjs/to-through/commit/cf656cf25ebc4b058333736fb41da66192097dae)) 14 | 15 | 16 | ### Miscellaneous Chores 17 | 18 | * Upgrade scaffold, dropping node <10 support ([#8](https://www.github.com/gulpjs/to-through/issues/8)) ([f095480](https://www.github.com/gulpjs/to-through/commit/f0954801ad61d277901edcba6fdbe3b002f818c9)) 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017, 2020-2021 Blaine Bublitz and Eric Schoffstall 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "to-through", 3 | "version": "3.0.0", 4 | "description": "Wrap a Readable stream in a Transform stream.", 5 | "author": "Gulp Team (https://gulpjs.com/)", 6 | "contributors": [ 7 | "Blaine Bublitz " 8 | ], 9 | "repository": "gulpjs/to-through", 10 | "license": "MIT", 11 | "engines": { 12 | "node": ">=10.13.0" 13 | }, 14 | "main": "index.js", 15 | "files": [ 16 | "LICENSE", 17 | "index.js" 18 | ], 19 | "scripts": { 20 | "lint": "eslint .", 21 | "pretest": "npm run lint", 22 | "test": "nyc mocha --async-only" 23 | }, 24 | "dependencies": { 25 | "streamx": "^2.12.5" 26 | }, 27 | "devDependencies": { 28 | "eslint": "^7.32.0", 29 | "eslint-config-gulp": "^5.0.1", 30 | "eslint-plugin-node": "^11.1.0", 31 | "expect": "^27.4.2", 32 | "mocha": "^8.4.0", 33 | "nyc": "^15.1.0", 34 | "readable-stream": "^3.6.0" 35 | }, 36 | "nyc": { 37 | "reporter": [ 38 | "lcov", 39 | "text-summary" 40 | ] 41 | }, 42 | "prettier": { 43 | "singleQuote": true 44 | }, 45 | "keywords": [ 46 | "transform", 47 | "readable", 48 | "through", 49 | "wrap" 50 | ] 51 | } 52 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # next.js build output 61 | .next 62 | 63 | # Garbage files 64 | .DS_Store 65 | 66 | # Test results 67 | test.xunit 68 | -------------------------------------------------------------------------------- /.github/workflows/dev.yml: -------------------------------------------------------------------------------- 1 | name: dev 2 | on: 3 | pull_request: 4 | push: 5 | branches: 6 | - master 7 | - main 8 | env: 9 | CI: true 10 | 11 | jobs: 12 | prettier: 13 | name: Format code 14 | runs-on: ubuntu-latest 15 | if: ${{ github.event_name == 'push' }} 16 | 17 | steps: 18 | - name: Checkout 19 | uses: actions/checkout@v2 20 | 21 | - name: Prettier 22 | uses: gulpjs/prettier_action@v3.0 23 | with: 24 | commit_message: 'chore: Run prettier' 25 | prettier_options: '--write .' 26 | 27 | test: 28 | name: Tests for Node ${{ matrix.node }} on ${{ matrix.os }} 29 | runs-on: ${{ matrix.os }} 30 | 31 | strategy: 32 | fail-fast: false 33 | matrix: 34 | node: [10, 12, 14, 16] 35 | os: [ubuntu-latest, windows-latest, macos-latest] 36 | 37 | steps: 38 | - name: Clone repository 39 | uses: actions/checkout@v2 40 | 41 | - name: Set Node.js version 42 | uses: actions/setup-node@v2 43 | with: 44 | node-version: ${{ matrix.node }} 45 | 46 | - run: node --version 47 | - run: npm --version 48 | 49 | - name: Install npm dependencies 50 | run: npm install 51 | 52 | - name: Run lint 53 | run: npm run lint 54 | 55 | - name: Run tests 56 | run: npm test 57 | 58 | - name: Coveralls 59 | uses: coverallsapp/github-action@v1.1.2 60 | with: 61 | github-token: ${{ secrets.GITHUB_TOKEN }} 62 | flag-name: ${{matrix.os}}-node-${{ matrix.node }} 63 | parallel: true 64 | 65 | coveralls: 66 | needs: test 67 | name: Finish up 68 | 69 | runs-on: ubuntu-latest 70 | steps: 71 | - name: Coveralls Finished 72 | uses: coverallsapp/github-action@v1.1.2 73 | with: 74 | github-token: ${{ secrets.GITHUB_TOKEN }} 75 | parallel-finished: true 76 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 | 5 |

6 | 7 | # to-through 8 | 9 | [![NPM version][npm-image]][npm-url] [![Downloads][downloads-image]][npm-url] [![Build Status][ci-image]][ci-url] [![Coveralls Status][coveralls-image]][coveralls-url] 10 | 11 | Wrap a `Readable` stream in a `Transform` stream. 12 | 13 | ## Usage 14 | 15 | ```js 16 | var { Readable } = require('streamx'); 17 | var concat = require('concat-stream'); 18 | var toThrough = require('to-through'); 19 | 20 | var readable = Readable.from([' ', 'hello', ' ', 'world']); 21 | 22 | // Can be used as a Readable or Transform 23 | var maybeTransform = toThrough(readable); 24 | 25 | Readable.from(['hi', ' ', 'there', ',']) 26 | .pipe(maybeTransform) 27 | .pipe( 28 | concat(function (result) { 29 | // result === 'hi there, hello world' 30 | }) 31 | ); 32 | ``` 33 | 34 | ## API 35 | 36 | ### `toThrough(readableStream)` 37 | 38 | Takes a `Readable` stream as the only argument and returns a `Transform` stream wrapper. Any data 39 | piped into the `Transform` stream is piped passed along before any data from the wrapped `Readable` is injected into the stream. 40 | 41 | ## License 42 | 43 | MIT 44 | 45 | 46 | [downloads-image]: https://img.shields.io/npm/dm/to-through.svg?style=flat-square 47 | [npm-url]: https://www.npmjs.com/package/to-through 48 | [npm-image]: https://img.shields.io/npm/v/to-through.svg?style=flat-square 49 | 50 | [ci-url]: https://github.com/gulpjs/to-through/actions?query=workflow:dev 51 | [ci-image]: https://img.shields.io/github/actions/workflow/status/gulpjs/to-through/dev.yml?branch=master&style=flat-square 52 | 53 | [coveralls-url]: https://coveralls.io/r/gulpjs/to-through 54 | [coveralls-image]: https://img.shields.io/coveralls/gulpjs/to-through/master.svg?style=flat-square 55 | 56 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Transform = require('streamx').Transform; 4 | 5 | // Based on help from @mafintosh via https://gist.github.com/mafintosh/92836a8d03df0ef41356e233e0f06382 6 | 7 | function toThrough(readable) { 8 | var highWaterMark = readable._readableState.highWaterMark; 9 | 10 | // Streamx uses 16384 as the default highWaterMark for everything and then 11 | // divides it by 1024 for objects 12 | // However, node's objectMode streams the number of objects as highWaterMark, so we need to 13 | // multiply the objectMode highWaterMark by 1024 to make it streamx compatible 14 | if (readable._readableState.objectMode) { 15 | highWaterMark = readable._readableState.highWaterMark * 1024; 16 | } 17 | 18 | var destroyedByError = false; 19 | var readableClosed = false; 20 | var readableEnded = false; 21 | 22 | function flush(cb) { 23 | var self = this; 24 | 25 | // Afer all writes have drained, we change the `_read` implementation 26 | self._read = function (cb) { 27 | readable.resume(); 28 | cb(); 29 | }; 30 | 31 | readable.on('data', onData); 32 | readable.once('error', onError); 33 | readable.once('end', onEnd); 34 | 35 | function cleanup() { 36 | readable.off('data', onData); 37 | readable.off('error', onError); 38 | readable.off('end', onEnd); 39 | } 40 | 41 | function onData(data) { 42 | var drained = self.push(data); 43 | // When the stream is not drained, we pause it because `_read` will be called later 44 | if (!drained) { 45 | readable.pause(); 46 | } 47 | } 48 | 49 | function onError(err) { 50 | cleanup(); 51 | cb(err); 52 | } 53 | 54 | function onEnd() { 55 | cleanup(); 56 | cb(); 57 | } 58 | } 59 | 60 | // Handle the case where a user destroyed the returned stream 61 | function predestroy() { 62 | // Only call destroy on the readable if this `predestroy` wasn't 63 | // caused via the readable having an `error` or `close` event 64 | if (destroyedByError) { 65 | return; 66 | } 67 | if (readableClosed) { 68 | return; 69 | } 70 | readable.destroy(new Error('Wrapper destroyed')); 71 | } 72 | 73 | var wrapper = new Transform({ 74 | highWaterMark: highWaterMark, 75 | flush: flush, 76 | predestroy: predestroy, 77 | }); 78 | 79 | // Forward errors from the underlying stream 80 | readable.once('error', onError); 81 | readable.once('end', onEnd); 82 | readable.once('close', onClose); 83 | 84 | function onError(err) { 85 | destroyedByError = true; 86 | wrapper.destroy(err); 87 | } 88 | 89 | function onEnd() { 90 | readableEnded = true; 91 | } 92 | 93 | function onClose() { 94 | readableClosed = true; 95 | // Only destroy the wrapper if the readable hasn't ended successfully 96 | if (!readableEnded) { 97 | wrapper.destroy(); 98 | } 99 | } 100 | 101 | var shouldFlow = true; 102 | wrapper.once('pipe', onPipe); 103 | wrapper.on('piping', onPiping); 104 | wrapper.on('newListener', onListener); 105 | 106 | function onPiping() { 107 | maybeFlow(); 108 | wrapper.off('piping', onPiping); 109 | wrapper.off('newListener', onListener); 110 | } 111 | 112 | function onListener(event) { 113 | // Once we've seen the data or readable event, check if we need to flow 114 | if (event === 'data' || event === 'readable') { 115 | onPiping(); 116 | } 117 | } 118 | 119 | function onPipe() { 120 | // If the wrapper is piped, disable flow 121 | shouldFlow = false; 122 | } 123 | 124 | function maybeFlow() { 125 | // If we need to flow, end the stream which triggers flush 126 | if (shouldFlow) { 127 | wrapper.end(); 128 | } 129 | } 130 | 131 | return wrapper; 132 | } 133 | 134 | module.exports = toThrough; 135 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var expect = require('expect'); 4 | 5 | var toThrough = require('../'); 6 | 7 | function isStringLike(item) { 8 | return typeof item === 'string' || Buffer.isBuffer(item); 9 | } 10 | 11 | function suite(moduleName) { 12 | var stream = require(moduleName); 13 | 14 | function concat(fn, opts) { 15 | opts = opts || {}; 16 | 17 | var items = []; 18 | 19 | return new stream.Writable( 20 | Object.assign({}, opts, { 21 | write: function (data, enc, cb) { 22 | if (typeof enc === 'function') { 23 | cb = enc; 24 | } 25 | 26 | setTimeout(function () { 27 | items.push(data); 28 | cb(); 29 | }, opts.timeout || 1); 30 | }, 31 | 32 | final: function (cb) { 33 | if (typeof fn === 'function') { 34 | if (items.every(isStringLike)) { 35 | fn(items.join('')); 36 | } else { 37 | fn(items); 38 | } 39 | } 40 | cb(); 41 | }, 42 | }) 43 | ); 44 | } 45 | 46 | describe('buffered (' + moduleName + ')', function () { 47 | // These tests ensure it automatically detects buffer mode 48 | 49 | var preContents = ['from', ' ', 'upstream', ' ']; 50 | var contents = ['hello', ' ', 'world', ' ', '123']; 51 | 52 | it('can wrap a Readable and be used as a Readable', function (done) { 53 | var readable = stream.Readable.from(contents, { objectMode: false }); 54 | 55 | function assert(result) { 56 | expect(result).toEqual(contents.join('')); 57 | } 58 | 59 | stream.pipeline([toThrough(readable), concat(assert)], done); 60 | }); 61 | 62 | it('can watch data event', function (done) { 63 | var to = toThrough(stream.Readable.from(contents, { objectMode: false })); 64 | var data = []; 65 | 66 | to.on('data', function (result) { 67 | data.push(result); 68 | }); 69 | 70 | to.on('end', function () { 71 | expect(data.join('')).toEqual(contents.join('')); 72 | done(); 73 | }); 74 | }); 75 | 76 | it('can wrap a Readable and be used as a Transform', function (done) { 77 | var readable = stream.Readable.from(contents, { objectMode: false }); 78 | 79 | function assert(result) { 80 | expect(result).toEqual(contents.join('')); 81 | } 82 | 83 | stream.pipeline( 84 | [ 85 | stream.Readable.from([], { objectMode: false }), 86 | toThrough(readable), 87 | concat(assert), 88 | ], 89 | done 90 | ); 91 | }); 92 | 93 | it('can wrap an empty Readable and be used as a Transform', function (done) { 94 | var readable = stream.Readable.from([], { objectMode: false }); 95 | 96 | function assert(result) { 97 | expect(result).toEqual(preContents.join('')); 98 | } 99 | 100 | stream.pipeline( 101 | [ 102 | stream.Readable.from(preContents, { objectMode: false }), 103 | toThrough(readable), 104 | concat(assert), 105 | ], 106 | done 107 | ); 108 | }); 109 | 110 | it('passes through all upstream before readable', function (done) { 111 | var readable = stream.Readable.from(contents, { objectMode: false }); 112 | 113 | function assert(result) { 114 | expect(result).toEqual(preContents.concat(contents).join('')); 115 | } 116 | 117 | stream.pipeline( 118 | [ 119 | stream.Readable.from(preContents, { objectMode: false }), 120 | toThrough(readable), 121 | concat(assert), 122 | ], 123 | done 124 | ); 125 | }); 126 | 127 | it('re-emits errors from readable before data', function (done) { 128 | var readable = new stream.Readable({ 129 | read: function (cb) { 130 | var err = new Error('boom'); 131 | if (typeof cb === 'function') { 132 | return cb(err); 133 | } 134 | 135 | this.destroy(err); 136 | }, 137 | }); 138 | 139 | function assert(err) { 140 | expect(err.message).toEqual('boom'); 141 | done(); 142 | } 143 | 144 | stream.pipeline( 145 | [ 146 | stream.Readable.from(preContents, { objectMode: false }), 147 | toThrough(readable), 148 | concat(), 149 | ], 150 | assert 151 | ); 152 | }); 153 | 154 | it('re-emits errors from readable after some data', function (done) { 155 | var items = ['hello']; 156 | var readable = new stream.Readable({ 157 | read: function (cb) { 158 | var chunk = items.shift(); 159 | if (chunk) { 160 | this.push(chunk); 161 | if (typeof cb === 'function') { 162 | cb(); 163 | } 164 | return; 165 | } 166 | 167 | var err = new Error('boom'); 168 | if (typeof cb === 'function') { 169 | return cb(err); 170 | } 171 | 172 | this.destroy(err); 173 | }, 174 | }); 175 | 176 | function assert(err) { 177 | expect(err.message).toEqual('boom'); 178 | done(); 179 | } 180 | 181 | stream.pipeline( 182 | [ 183 | stream.Readable.from(preContents, { objectMode: false }), 184 | toThrough(readable), 185 | concat(), 186 | ], 187 | assert 188 | ); 189 | }); 190 | 191 | it('does not flush the stream if not piped before nextTick', function (done) { 192 | var readable = stream.Readable.from(contents, { objectMode: false }); 193 | 194 | var wrapped = toThrough(readable); 195 | 196 | function assert(result) { 197 | expect(result).toEqual(preContents.concat(contents).join('')); 198 | } 199 | 200 | process.nextTick(function () { 201 | stream.pipeline( 202 | [stream.Readable.from(preContents), wrapped, concat(assert)], 203 | done 204 | ); 205 | }); 206 | }); 207 | 208 | it('destroys the readable if the wrapper is destroyed', function (done) { 209 | var readable = stream.Readable.from(contents, { objectMode: false }); 210 | 211 | var wrapped = toThrough(readable); 212 | 213 | readable.on('error', function (err) { 214 | expect(err.message).toEqual('Wrapper destroyed'); 215 | done(); 216 | }); 217 | 218 | wrapped.destroy(); 219 | }); 220 | 221 | it('destroys the wrapper if the readable is destroyed', function (done) { 222 | var readable = stream.Readable.from(contents, { objectMode: false }); 223 | 224 | var wrapped = toThrough(readable); 225 | 226 | wrapped.on('close', function () { 227 | expect(wrapped.destroyed).toEqual(true); 228 | done(); 229 | }); 230 | readable.on('error', function (err) { 231 | // To ensure another error isn't surfaced 232 | expect(err).toBeUndefined(); 233 | }); 234 | 235 | readable.destroy(); 236 | }); 237 | }); 238 | 239 | describe('object mode (' + moduleName + ')', function () { 240 | // These tests ensure it automatically detects objectMode 241 | 242 | var preContents = [{ value: -2 }, { value: -1 }, { value: 0 }]; 243 | var contents = [ 244 | { value: 1 }, 245 | { value: 2 }, 246 | { value: 3 }, 247 | { value: 4 }, 248 | { value: 5 }, 249 | { value: 6 }, 250 | { value: 7 }, 251 | { value: 8 }, 252 | { value: 9 }, 253 | { value: 10 }, 254 | { value: 11 }, 255 | { value: 12 }, 256 | { value: 13 }, 257 | { value: 14 }, 258 | { value: 15 }, 259 | { value: 16 }, 260 | { value: 17 }, 261 | { value: 18 }, 262 | { value: 19 }, 263 | { value: 20 }, 264 | ]; 265 | 266 | it('can wrap a Readable and be used as a Readable', function (done) { 267 | var readable = stream.Readable.from(contents); 268 | 269 | function assert(result) { 270 | expect(result).toEqual(contents); 271 | } 272 | 273 | stream.pipeline( 274 | [toThrough(readable), concat(assert, { objectMode: true })], 275 | done 276 | ); 277 | }); 278 | 279 | it('can wrap a Readable and be used as a Transform', function (done) { 280 | var readable = stream.Readable.from(contents); 281 | 282 | function assert(result) { 283 | expect(result).toEqual(contents); 284 | } 285 | 286 | stream.pipeline( 287 | [ 288 | stream.Readable.from([]), 289 | toThrough(readable), 290 | concat(assert, { objectMode: true }), 291 | ], 292 | done 293 | ); 294 | }); 295 | 296 | it('passes through all upstream before readable', function (done) { 297 | var readable = stream.Readable.from(contents); 298 | 299 | function assert(result) { 300 | expect(result).toEqual(preContents.concat(contents)); 301 | } 302 | 303 | stream.pipeline( 304 | [ 305 | stream.Readable.from(preContents), 306 | toThrough(readable), 307 | concat(assert, { objectMode: true }), 308 | ], 309 | done 310 | ); 311 | }); 312 | 313 | it('inherits the highWaterMark of the wrapped stream', function (done) { 314 | this.timeout(10000); 315 | 316 | var readable = stream.Readable.from(contents, { 317 | highWaterMark: moduleName === 'streamx' ? 1024 : 1, 318 | }); 319 | 320 | function assert(result) { 321 | expect(result).toEqual(preContents.concat(contents)); 322 | } 323 | 324 | stream.pipeline( 325 | [ 326 | stream.Readable.from(preContents), 327 | toThrough(readable), 328 | concat(assert, { objectMode: true, timeout: 250 }), 329 | ], 330 | done 331 | ); 332 | }); 333 | 334 | it('respects highWaterMark of the output stream', function (done) { 335 | this.timeout(10000); 336 | 337 | var readable = stream.Readable.from(contents); 338 | 339 | function assert(result) { 340 | expect(result).toEqual(preContents.concat(contents)); 341 | } 342 | 343 | stream.pipeline( 344 | [ 345 | stream.Readable.from(preContents), 346 | toThrough(readable), 347 | concat(assert, { highWaterMark: 1, objectMode: true, timeout: 250 }), 348 | ], 349 | done 350 | ); 351 | }); 352 | 353 | it('respects highWaterMark of itself and the output stream', function (done) { 354 | this.timeout(10000); 355 | 356 | var readable = stream.Readable.from(contents, { 357 | highWaterMark: moduleName === 'streamx' ? 1024 : 1, 358 | }); 359 | 360 | function assert(result) { 361 | expect(result).toEqual(preContents.concat(contents)); 362 | } 363 | 364 | stream.pipeline( 365 | [ 366 | stream.Readable.from(preContents), 367 | toThrough(readable), 368 | concat(assert, { highWaterMark: 1, objectMode: true, timeout: 250 }), 369 | ], 370 | done 371 | ); 372 | }); 373 | 374 | it('does not flush the stream if not piped before nextTick', function (done) { 375 | var readable = stream.Readable.from(contents); 376 | 377 | var wrapped = toThrough(readable); 378 | 379 | function assert(result) { 380 | expect(result).toEqual(preContents.concat(contents)); 381 | } 382 | 383 | process.nextTick(function () { 384 | stream.pipeline( 385 | [ 386 | stream.Readable.from(preContents), 387 | wrapped, 388 | concat(assert, { objectMode: true }), 389 | ], 390 | done 391 | ); 392 | }); 393 | }); 394 | }); 395 | } 396 | 397 | suite('stream'); 398 | suite('streamx'); 399 | suite('readable-stream'); 400 | --------------------------------------------------------------------------------