├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── index.js ├── package.json └── test └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store* 2 | node_modules 3 | *.log 4 | coverage 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | node_js: 2 | - '4' 3 | - '5' 4 | sudo: false 5 | language: node_js 6 | script: "npm run-script test-travis" 7 | after_script: "npm install coveralls@2 && cat ./coverage/lcov.info | coveralls" 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2014 Jonathan Ong me@jongleberry.com 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Stream to Array 2 | 3 | > **OBSOLETE: since node@18, there is now a [stream.toArray()](https://github.com/stream-utils/stream-to-array/issues/26) function** 4 | 5 | [![NPM version][npm-image]][npm-url] 6 | [![Build status][travis-image]][travis-url] 7 | [![Test coverage][coveralls-image]][coveralls-url] 8 | [![Dependency Status][david-image]][david-url] 9 | [![License][license-image]][license-url] 10 | [![Downloads][downloads-image]][downloads-url] 11 | 12 | Concatenate a readable stream's data into a single array. 13 | 14 | You may also be interested in: 15 | 16 | - [raw-body](https://github.com/stream-utils/raw-body) for strings 17 | 18 | ## API 19 | 20 | ```js 21 | var toArray = require('stream-to-array') 22 | ``` 23 | 24 | ### toArray([stream], [callback(err, arr)]) 25 | 26 | Returns all the data objects in an array. 27 | This is useful for streams in object mode if you want to just use an array. 28 | 29 | ```js 30 | var stream = new Stream.Readable() 31 | toArray(stream, function (err, arr) { 32 | assert.ok(Array.isArray(arr)) 33 | }) 34 | ``` 35 | 36 | If `stream` is not defined, it is assumed that `this` is a stream. 37 | 38 | ```js 39 | var stream = new Stream.Readable() 40 | stream.toArray = toArray 41 | stream.toArray(function (err, arr) { 42 | 43 | }) 44 | ``` 45 | 46 | If `callback` is not defined, then it returns a promise. 47 | 48 | ```js 49 | toArray(stream) 50 | .then(function (parts) { 51 | 52 | }) 53 | ``` 54 | 55 | If you want to return a buffer, just use `Buffer.concat(arr)` 56 | 57 | ```js 58 | toArray(stream) 59 | .then(function (parts) { 60 | const buffers = parts 61 | .map(part => util.isBuffer(part) ? part : Buffer.from(part)); 62 | return Buffer.concat(buffers); 63 | }) 64 | ``` 65 | 66 | [npm-image]: https://img.shields.io/npm/v/stream-to-array.svg?style=flat-square 67 | [npm-url]: https://npmjs.org/package/stream-to-array 68 | [github-tag]: http://img.shields.io/github/tag/stream-utils/stream-to-array.svg?style=flat-square 69 | [github-url]: https://github.com/stream-utils/stream-to-array/tags 70 | [travis-image]: https://img.shields.io/travis/stream-utils/stream-to-array.svg?style=flat-square 71 | [travis-url]: https://travis-ci.org/stream-utils/stream-to-array 72 | [coveralls-image]: https://img.shields.io/coveralls/stream-utils/stream-to-array.svg?style=flat-square 73 | [coveralls-url]: https://coveralls.io/r/stream-utils/stream-to-array?branch=master 74 | [david-image]: http://img.shields.io/david/stream-utils/stream-to-array.svg?style=flat-square 75 | [david-url]: https://david-dm.org/stream-utils/stream-to-array 76 | [license-image]: http://img.shields.io/npm/l/stream-to-array.svg?style=flat-square 77 | [license-url]: LICENSE 78 | [downloads-image]: http://img.shields.io/npm/dm/stream-to-array.svg?style=flat-square 79 | [downloads-url]: https://npmjs.org/package/stream-to-array 80 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 2 | var Promise = require('any-promise') 3 | 4 | module.exports = function (stream, done) { 5 | if (!stream) { 6 | // no arguments, meaning stream = this 7 | stream = this 8 | } else if (typeof stream === 'function') { 9 | // stream = this, callback passed 10 | done = stream 11 | stream = this 12 | } 13 | 14 | var deferred 15 | if (!stream.readable) deferred = Promise.resolve([]) 16 | else deferred = new Promise(function (resolve, reject) { 17 | // stream is already ended 18 | if (!stream.readable) return resolve([]) 19 | 20 | var arr = [] 21 | 22 | stream.on('data', onData) 23 | stream.on('end', onEnd) 24 | stream.on('error', onError) 25 | stream.on('close', onClose) 26 | 27 | function onData(doc) { 28 | arr.push(doc) 29 | } 30 | 31 | function onEnd(err) { 32 | resolve(arr) 33 | cleanup() 34 | } 35 | 36 | function onError(err) { 37 | reject(err) 38 | cleanup() 39 | } 40 | 41 | function onClose() { 42 | resolve(arr) 43 | cleanup() 44 | } 45 | 46 | function cleanup() { 47 | arr = null 48 | stream.removeListener('data', onData) 49 | stream.removeListener('end', onEnd) 50 | stream.removeListener('error', onEnd) 51 | stream.removeListener('close', onClose) 52 | } 53 | }) 54 | 55 | if (typeof done === 'function') { 56 | deferred.then(function (arr) { done(null, arr) }, done) 57 | } 58 | 59 | return deferred 60 | } 61 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "stream-to-array", 3 | "description": "Concatenate a readable stream's data into a single array", 4 | "version": "2.3.0", 5 | "author": { 6 | "name": "Jonathan Ong", 7 | "email": "me@jongleberry.com", 8 | "url": "http://jongleberry.com", 9 | "twitter": "https://twitter.com/jongleberry" 10 | }, 11 | "license": "MIT", 12 | "repository": "stream-utils/stream-to-array", 13 | "dependencies": { 14 | "any-promise": "^1.1.0" 15 | }, 16 | "devDependencies": { 17 | "bluebird": "^3.1.1", 18 | "istanbul": "^0.4.2", 19 | "mocha": "^3.1.2" 20 | }, 21 | "scripts": { 22 | "test": "mocha --reporter spec --bail", 23 | "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot", 24 | "test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter dot" 25 | }, 26 | "files": [ 27 | "index.js" 28 | ], 29 | "keywords": [ 30 | "stream", 31 | "streams", 32 | "buffer", 33 | "array", 34 | "concat" 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | 2 | var assert = require('assert') 3 | var stream = require('stream') 4 | var path = require('path') 5 | var fs = require('fs') 6 | 7 | var toArray = require('..') 8 | 9 | var file = path.join(__dirname, 'index.js') 10 | 11 | function emptyStream() { 12 | var s = new stream() 13 | process.nextTick(function () { 14 | s.emit('end') 15 | }) 16 | return s 17 | } 18 | 19 | function closedStream() { 20 | var s = new stream.Readable(); 21 | s._read = function () { 22 | } 23 | process.nextTick(function () { 24 | s.emit('close') 25 | }) 26 | return s 27 | } 28 | 29 | describe('Stream To Array', function () { 30 | describe('as a function', function () { 31 | it('should work', function (done) { 32 | toArray(fs.createReadStream(file), function (err, arr) { 33 | if (err) 34 | return done(err) 35 | 36 | assert.ok(Array.isArray(arr)) 37 | assert.ok(arr.length) 38 | 39 | done() 40 | }) 41 | }) 42 | 43 | it('should work as a promise', function () { 44 | return toArray(fs.createReadStream(file)).then(function (arr) { 45 | assert.ok(Array.isArray(arr)) 46 | assert.ok(arr.length) 47 | }) 48 | }) 49 | 50 | it('should work as a promise with zalgo', function () { 51 | return toArray(emptyStream()).then(function (arr) { 52 | assert.ok(Array.isArray(arr)) 53 | assert.equal(arr.length, 0) 54 | }) 55 | }) 56 | 57 | it('should work as a promise with chucky', function () { 58 | return toArray(closedStream()).then(function (arr) { 59 | assert.ok(Array.isArray(arr)) 60 | assert.equal(arr.length, 0) 61 | }) 62 | }) 63 | 64 | it('should not swallow errors', function (done) { 65 | // remove all current listeners, specifically mocha's 66 | var listeners = process.listeners('uncaughtException') 67 | process.removeAllListeners('uncaughtException') 68 | 69 | // add our own 70 | process.on('uncaughtException', onUncaughtException) 71 | 72 | // TODO: move this testing logic to a module 73 | function onUncaughtException (err) { 74 | // remove our own listener 75 | process.removeListener('uncaughtException', onUncaughtException) 76 | 77 | // add all previous listeners 78 | listeners.forEach(function (listener) { 79 | process.on('uncaughtException', listener) 80 | }) 81 | 82 | done() 83 | } 84 | 85 | toArray(emptyStream(), function () { 86 | // this should be uncaught 87 | throw new Error('BOOM') 88 | }).catch(function (err) { 89 | if (err) return done(err) 90 | }) 91 | }) 92 | 93 | it('should handle stream errors', function (done) { 94 | toArray(fs.createReadStream("madeupfile.jpg")) 95 | .then(function () { 96 | done(new Error("Promise should be rejected")) 97 | }) 98 | .catch(function (err) { 99 | done() 100 | }) 101 | }) 102 | }) 103 | 104 | describe('as a method', function () { 105 | it('should work', function (done) { 106 | var stream = fs.createReadStream(file) 107 | stream.toArray = toArray 108 | stream.toArray(function (err, arr) { 109 | if (err) 110 | return done(err) 111 | 112 | assert.ok(Array.isArray(arr)) 113 | assert.ok(arr.length) 114 | 115 | done() 116 | }) 117 | }) 118 | 119 | it('should work as a promise', function () { 120 | var stream = fs.createReadStream(file) 121 | stream.toArray = toArray 122 | return stream.toArray().then(function (arr) { 123 | assert.ok(Array.isArray(arr)) 124 | assert.ok(arr.length) 125 | }) 126 | }) 127 | 128 | it('should work as a promise with zalgo', function () { 129 | var stream = emptyStream() 130 | stream.toArray = toArray 131 | return stream.toArray().then(function (arr) { 132 | assert.ok(Array.isArray(arr)) 133 | assert.equal(arr.length, 0) 134 | }) 135 | }) 136 | 137 | it('should work as a promise with chucky', function () { 138 | var stream = closedStream() 139 | stream.toArray = toArray 140 | return stream.toArray().then(function (arr) { 141 | assert.ok(Array.isArray(arr)) 142 | assert.equal(arr.length, 0) 143 | }) 144 | }) 145 | }) 146 | }) 147 | --------------------------------------------------------------------------------