7
7
isNodeStream,
8
8
isReadable,
9
9
isWritable,
10
+ isWebStream,
11
+ isTransformStream,
12
+ isWritableStream,
13
+ isReadableStream,
10
14
} = require ( 'internal/streams/utils' ) ;
11
15
const {
12
16
AbortError,
@@ -15,6 +19,7 @@ const {
15
19
ERR_MISSING_ARGS ,
16
20
} ,
17
21
} = require ( 'internal/errors' ) ;
22
+ const eos = require ( 'internal/streams/end-of-stream' ) ;
18
23
19
24
module . exports = function compose ( ...streams ) {
20
25
if ( streams . length === 0 ) {
@@ -57,9 +62,8 @@ module.exports = function compose(...streams) {
57
62
}
58
63
}
59
64
60
- let ondrain ;
61
- let onfinish ;
62
- let onreadable ;
65
+ let writableEndDestructor ;
66
+ let readableEndDestructor ;
63
67
let onclose ;
64
68
let d ;
65
69
@@ -79,8 +83,8 @@ module.exports = function compose(...streams) {
79
83
const head = streams [ 0 ] ;
80
84
const tail = pipeline ( streams , onfinished ) ;
81
85
82
- const writable = ! ! isWritable ( head ) ;
83
- const readable = ! ! isReadable ( tail ) ;
86
+ const writable = ! ! ( isWritable ( head ) || isWritableStream ( head ) || isTransformStream ( head ) ) ;
87
+ const readable = ! ! ( isReadable ( tail ) || isReadableStream ( tail ) || isTransformStream ( tail ) ) ;
84
88
85
89
// TODO(ronag): Avoid double buffering.
86
90
// Implement Writable/Readable/Duplex traits.
@@ -94,15 +98,51 @@ module.exports = function compose(...streams) {
94
98
} ) ;
95
99
96
100
if ( writable ) {
97
- d . _write = function ( chunk , encoding , callback ) {
101
+ writableEndDestructor = makeWritableEnd ( d , head , tail ) ;
102
+ }
103
+
104
+ if ( readable ) {
105
+ readableEndDestructor = makeReadableEnd ( d , head , tail ) ;
106
+ }
107
+
108
+ d . _destroy = function ( err , callback ) {
109
+ if ( ! err && onclose !== null ) {
110
+ err = new AbortError ( ) ;
111
+ }
112
+
113
+ if ( readableEndDestructor ) {
114
+ readableEndDestructor ( ) ;
115
+ }
116
+
117
+ if ( writableEndDestructor ) {
118
+ writableEndDestructor ( ) ;
119
+ }
120
+
121
+ if ( onclose === null ) {
122
+ callback ( err ) ;
123
+ } else {
124
+ onclose = callback ;
125
+ destroyer ( tail , err ) ;
126
+ }
127
+ } ;
128
+
129
+ return d ;
130
+ } ;
131
+
132
+ function makeWritableEnd ( duplex , head , tail ) {
133
+ let ondrain ;
134
+ let onfinish ;
135
+
136
+ if ( isNodeStream ( head ) ) {
137
+ duplex . _write = function ( chunk , encoding , callback ) {
98
138
if ( head . write ( chunk , encoding ) ) {
99
139
callback ( ) ;
100
140
} else {
101
141
ondrain = callback ;
102
142
}
103
143
} ;
104
144
105
- d . _final = function ( callback ) {
145
+ duplex . _final = function ( callback ) {
106
146
head . end ( ) ;
107
147
onfinish = callback ;
108
148
} ;
@@ -114,17 +154,61 @@ module.exports = function compose(...streams) {
114
154
cb ( ) ;
115
155
}
116
156
} ) ;
157
+ } else if ( isWebStream ( head ) ) {
158
+ const writable = isTransformStream ( head ) ? head . writable : head ;
159
+ const writer = writable . getWriter ( ) ;
160
+
161
+ duplex . _write = async function ( chunk , encoding , callback ) {
162
+ try {
163
+ await writer . ready ;
164
+ writer . write ( chunk ) . catch ( ( ) => { } ) ;
165
+ callback ( ) ;
166
+ } catch ( err ) {
167
+ callback ( err ) ;
168
+ }
169
+ } ;
117
170
171
+ duplex . _final = async function ( callback ) {
172
+ try {
173
+ await writer . ready ;
174
+ writer . close ( ) ;
175
+ onfinish = callback ;
176
+ } catch ( err ) {
177
+ callback ( err ) ;
178
+ }
179
+ } ;
180
+ }
181
+
182
+ if ( isNodeStream ( tail ) ) {
118
183
tail . on ( 'finish' , function ( ) {
119
184
if ( onfinish ) {
120
185
const cb = onfinish ;
121
186
onfinish = null ;
122
187
cb ( ) ;
123
188
}
124
189
} ) ;
190
+ } else if ( isWebStream ( tail ) ) {
191
+ const readable = isTransformStream ( tail ) ? tail . readable : tail ;
192
+ eos ( readable , ( ) => {
193
+ if ( onfinish ) {
194
+ const cb = onfinish ;
195
+ onfinish = null ;
196
+ cb ( ) ;
197
+ }
198
+ } ) ;
125
199
}
126
200
127
- if ( readable ) {
201
+ function destructor ( ) {
202
+ ondrain = null ;
203
+ onfinish = null ;
204
+ }
205
+
206
+ return destructor ;
207
+ }
208
+
209
+ function makeReadableEnd ( duplex , head , tail ) {
210
+ let onreadable ;
211
+ if ( isNodeStream ( tail ) ) {
128
212
tail . on ( 'readable' , function ( ) {
129
213
if ( onreadable ) {
130
214
const cb = onreadable ;
@@ -134,41 +218,43 @@ module.exports = function compose(...streams) {
134
218
} ) ;
135
219
136
220
tail . on ( 'end' , function ( ) {
137
- d . push ( null ) ;
221
+ duplex . push ( null ) ;
138
222
} ) ;
139
223
140
- d . _read = function ( ) {
224
+ duplex . _read = function ( ) {
141
225
while ( true ) {
142
226
const buf = tail . read ( ) ;
143
-
144
227
if ( buf === null ) {
145
- onreadable = d . _read ;
228
+ onreadable = duplex . _read ;
146
229
return ;
147
230
}
148
231
149
- if ( ! d . push ( buf ) ) {
232
+ if ( ! duplex . push ( buf ) ) {
150
233
return ;
151
234
}
152
235
}
153
236
} ;
154
- }
237
+ } else if ( isWebStream ( tail ) ) {
238
+ const readable = isTransformStream ( tail ) ? tail . readable : tail ;
239
+ const reader = readable . getReader ( ) ;
240
+ duplex . _read = async function ( ) {
241
+ while ( true ) {
242
+ const { value, done } = await reader . read ( ) ;
243
+ if ( done ) {
244
+ duplex . push ( null ) ;
245
+ return ;
246
+ }
155
247
156
- d . _destroy = function ( err , callback ) {
157
- if ( ! err && onclose !== null ) {
158
- err = new AbortError ( ) ;
159
- }
248
+ if ( ! duplex . push ( value ) ) {
249
+ return ;
250
+ }
251
+ }
252
+ } ;
253
+ }
160
254
255
+ function destructor ( ) {
161
256
onreadable = null ;
162
- ondrain = null ;
163
- onfinish = null ;
164
-
165
- if ( onclose === null ) {
166
- callback ( err ) ;
167
- } else {
168
- onclose = callback ;
169
- destroyer ( tail , err ) ;
170
- }
171
- } ;
257
+ }
172
258
173
- return d ;
174
- } ;
259
+ return destructor ;
260
+ }
0 commit comments