Skip to content

Commit 18cfa86

Browse files
achingbrainhugomrdias
authored andcommitted
feat: support old school streams (#12)
In order not to break our users, this PR adds support for the [`readable-stream`](https://www.npmjs.com/package/readable-stream) module @v2 and @V3.
1 parent 8534de8 commit 18cfa86

File tree

3 files changed

+135
-1
lines changed

3 files changed

+135
-1
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@
4646
"dirty-chai": "^2.0.1",
4747
"electron": "^6.0.6",
4848
"electron-mocha": "^8.0.3",
49-
"pull-stream": "^3.6.13"
49+
"pull-stream": "^3.6.13",
50+
"readable-stream-2": "npm:readable-stream@^2.0.0"
5051
},
5152
"contributors": [
5253
"Alan Shaw <alan.shaw@protocol.ai>",

src/files/normalise-input.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ const { Buffer } = require('buffer')
55
const pullStreamToIterable = require('pull-stream-to-async-iterator')
66
const { isSource } = require('is-pull-stream')
77
const globalThis = require('../globalthis')
8+
const { Readable } = require('stream')
9+
const Readable3 = require('readable-stream')
810

911
/*
1012
* Transform one of:
@@ -20,6 +22,7 @@ const globalThis = require('../globalthis')
2022
* { path, content: Iterable<Bytes> } [single file]
2123
* { path, content: AsyncIterable<Bytes> } [single file]
2224
* { path, content: PullStream<Bytes> } [single file]
25+
* { path, content: Readable<Bytes> } [single file]
2326
* Iterable<Number> [single file]
2427
* Iterable<Bytes> [single file]
2528
* Iterable<Bloby> [multiple files]
@@ -31,6 +34,7 @@ const globalThis = require('../globalthis')
3134
* Iterable<{ path, content: Iterable<Bytes> }> [multiple files]
3235
* Iterable<{ path, content: AsyncIterable<Bytes> }> [multiple files]
3336
* Iterable<{ path, content: PullStream<Bytes> }> [multiple files]
37+
* Iterable<{ path, content: Readable<Bytes> }> [multiple files]
3438
* AsyncIterable<Bytes> [single file]
3539
* AsyncIterable<Bloby> [multiple files]
3640
* AsyncIterable<String> [multiple files]
@@ -41,6 +45,7 @@ const globalThis = require('../globalthis')
4145
* AsyncIterable<{ path, content: Iterable<Bytes> }> [multiple files]
4246
* AsyncIterable<{ path, content: AsyncIterable<Bytes> }> [multiple files]
4347
* AsyncIterable<{ path, content: PullStream<Bytes> }> [multiple files]
48+
* AsyncIterable<{ path, content: Readable<Bytes> }> [multiple files]
4449
* PullStream<Bytes> [single file]
4550
* PullStream<Bloby> [multiple files]
4651
* PullStream<String> [multiple files]
@@ -51,6 +56,18 @@ const globalThis = require('../globalthis')
5156
* PullStream<{ path, content: Iterable<Bytes> }> [multiple files]
5257
* PullStream<{ path, content: AsyncIterable<Bytes> }> [multiple files]
5358
* PullStream<{ path, content: PullStream<Bytes> }> [multiple files]
59+
* PullStream<{ path, content: Readable<Bytes> }> [multiple files]
60+
* Readable<Bytes> [single file]
61+
* Readable<Bloby> [multiple files]
62+
* Readable<String> [multiple files]
63+
* Readable<{ path, content: Bytes }> [multiple files]
64+
* Readable<{ path, content: Bloby }> [multiple files]
65+
* Readable<{ path, content: String }> [multiple files]
66+
* Readable<{ path, content: Iterable<Number> }> [multiple files]
67+
* Readable<{ path, content: Iterable<Bytes> }> [multiple files]
68+
* Readable<{ path, content: AsyncIterable<Bytes> }> [multiple files]
69+
* Readable<{ path, content: PullStream<Bytes> }> [multiple files]
70+
* Readable<{ path, content: Readable<Bytes> }> [multiple files]
5471
* ```
5572
* Into:
5673
*
@@ -82,6 +99,11 @@ module.exports = function normaliseInput (input) {
8299
})()
83100
}
84101

102+
// Readable<?>
103+
if (isOldReadable(input)) {
104+
input = upgradeOldStream(input)
105+
}
106+
85107
// Iterable<?>
86108
if (input[Symbol.iterator]) {
87109
return (async function * () { // eslint-disable-line require-await
@@ -213,6 +235,11 @@ function toAsyncIterable (input) {
213235
return blobToAsyncGenerator(input)
214236
}
215237

238+
// Readable<?>
239+
if (isOldReadable(input)) {
240+
input = upgradeOldStream(input)
241+
}
242+
216243
// Iterator<?>
217244
if (input[Symbol.iterator]) {
218245
return (async function * () { // eslint-disable-line require-await
@@ -259,6 +286,14 @@ function toAsyncIterable (input) {
259286
throw errCode(new Error(`Unexpected input: ${input}`, 'ERR_UNEXPECTED_INPUT'))
260287
}
261288

289+
function isOldReadable (obj) {
290+
if (obj[Symbol.iterator] || obj[Symbol.asyncIterator]) {
291+
return false
292+
}
293+
294+
return Boolean(obj.readable)
295+
}
296+
262297
function toBuffer (chunk) {
263298
return isBytes(chunk) ? chunk : Buffer.from(chunk)
264299
}
@@ -276,6 +311,17 @@ function isFileObject (obj) {
276311
return typeof obj === 'object' && (obj.path || obj.content)
277312
}
278313

314+
function upgradeOldStream (stream) {
315+
if (stream[Symbol.asyncIterator] || stream[Symbol.iterator]) {
316+
return stream
317+
}
318+
319+
// in the browser the stream.Readable is not an async iterator but readble-stream@3 is...
320+
stream[Symbol.asyncIterator] = Readable.prototype[Symbol.asyncIterator] || Readable3.prototype[Symbol.asyncIterator]
321+
322+
return stream
323+
}
324+
279325
function blobToAsyncGenerator (blob) {
280326
if (typeof blob.stream === 'function') {
281327
// firefox < 69 does not support blob.stream()

test/files/normalise-input.spec.js

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ const { supportsFileReader } = require('../../src/supports')
88
const { Buffer } = require('buffer')
99
const all = require('async-iterator-all')
1010
const pull = require('pull-stream')
11+
const Readable2 = require('readable-stream-2')
12+
const Readable3 = require('readable-stream')
13+
const ReadableNode = require('stream').Readable
1114
const globalThis = require('../../src/globalthis')
1215

1316
chai.use(dirtyChai)
@@ -56,6 +59,42 @@ function pullStreamOf (thing) {
5659
return pull.values([thing])
5760
}
5861

62+
function readable2Of (thing) {
63+
const stream = new Readable2({
64+
objectMode: true,
65+
read () {
66+
this.push(thing)
67+
this.push(null)
68+
}
69+
})
70+
71+
return stream
72+
}
73+
74+
function readable3Of (thing) {
75+
const stream = new Readable3({
76+
objectMode: true,
77+
read () {
78+
this.push(thing)
79+
this.push(null)
80+
}
81+
})
82+
83+
return stream
84+
}
85+
86+
function readableNodeOf (thing) {
87+
const stream = new ReadableNode({
88+
objectMode: true,
89+
read () {
90+
this.push(thing)
91+
this.push(null)
92+
}
93+
})
94+
95+
return stream
96+
}
97+
5998
describe('normalise-input', function () {
6099
function testInputType (content, name, isBytes) {
61100
it(name, async function () {
@@ -74,6 +113,18 @@ describe('normalise-input', function () {
74113
it(`PullStream<${name}>`, async function () {
75114
await testContent(pullStreamOf(content))
76115
})
116+
117+
it(`Readable2<${name}>`, async function () {
118+
await testContent(readable2Of(content))
119+
})
120+
121+
it(`Readable3<${name}>`, async function () {
122+
await testContent(readable3Of(content))
123+
})
124+
125+
it(`ReadableNode<${name}>`, async function () {
126+
await testContent(readableNodeOf(content))
127+
})
77128
}
78129

79130
it(`{ path: '', content: ${name} }`, async function () {
@@ -92,6 +143,18 @@ describe('normalise-input', function () {
92143
it(`{ path: '', content: PullStream<${name}> }`, async function () {
93144
await testContent({ path: '', content: pullStreamOf(content) })
94145
})
146+
147+
it(`{ path: '', content: Readable2<${name}> }`, async function () {
148+
await testContent({ path: '', content: readable2Of(content) })
149+
})
150+
151+
it(`{ path: '', content: Readable3<${name}> }`, async function () {
152+
await testContent({ path: '', content: readable3Of(content) })
153+
})
154+
155+
it(`{ path: '', content: ReadableNode<${name}> }`, async function () {
156+
await testContent({ path: '', content: readableNodeOf(content) })
157+
})
95158
}
96159

97160
it(`Iterable<{ path: '', content: ${name} }`, async function () {
@@ -106,6 +169,18 @@ describe('normalise-input', function () {
106169
await testContent(pullStreamOf({ path: '', content }))
107170
})
108171

172+
it(`Readable2<{ path: '', content: ${name} }`, async function () {
173+
await testContent(readable2Of({ path: '', content }))
174+
})
175+
176+
it(`Readable3<{ path: '', content: ${name} }`, async function () {
177+
await testContent(readable3Of({ path: '', content }))
178+
})
179+
180+
it(`ReadableNode<{ path: '', content: ${name} }`, async function () {
181+
await testContent(readableNodeOf({ path: '', content }))
182+
})
183+
109184
if (isBytes) {
110185
it(`Iterable<{ path: '', content: Iterable<${name}> }>`, async function () {
111186
await testContent(iterableOf({ path: '', content: iterableOf(content) }))
@@ -126,6 +201,18 @@ describe('normalise-input', function () {
126201
it(`PullStream<{ path: '', content: PullStream<${name}> }>`, async function () {
127202
await testContent(pullStreamOf({ path: '', content: pullStreamOf(content) }))
128203
})
204+
205+
it(`Readable2<{ path: '', content: Readable2<${name}> }>`, async function () {
206+
await testContent(readable2Of({ path: '', content: readable2Of(content) }))
207+
})
208+
209+
it(`Readable3<{ path: '', content: Readable3<${name}> }>`, async function () {
210+
await testContent(readable3Of({ path: '', content: readable3Of(content) }))
211+
})
212+
213+
it(`ReadableNode<{ path: '', content: Readable3<${name}> }>`, async function () {
214+
await testContent(readableNodeOf({ path: '', content: readableNodeOf(content) }))
215+
})
129216
}
130217
}
131218

0 commit comments

Comments
 (0)