2
2
3
3
const errCode = require ( 'err-code' )
4
4
const { Buffer } = require ( 'buffer' )
5
+ const pullStreamToIterable = require ( 'pull-stream-to-async-iterator' )
5
6
6
7
/*
7
8
* Transform one of:
8
9
*
9
10
* ```
10
- * Buffer|ArrayBuffer|TypedArray
11
- * Blob|File
12
- * { path, content: Blob }
13
- * { path, content: String }
14
- * { path, content: Iterable<Number> }
15
- * { path, content: Iterable<Buffer> }
16
- * { path, content: Iterable<Iterable<Number>> }
17
- * { path, content: AsyncIterable<Iterable<Number>> }
18
- * String
19
- * Iterable<Number>
20
- * Iterable<Buffer>
21
- * Iterable<Blob>
22
- * Iterable<{ path, content: Buffer }>
23
- * Iterable<{ path, content: Blob }>
24
- * Iterable<{ path, content: Iterable<Number> }>
25
- * Iterable<{ path, content: AsyncIterable<Buffer> }>
26
- * AsyncIterable<Buffer>
27
- * AsyncIterable<{ path, content: Buffer }>
28
- * AsyncIterable<{ path, content: Blob }>
29
- * AsyncIterable<{ path, content: Iterable<Buffer> }>
30
- * AsyncIterable<{ path, content: AsyncIterable<Buffer> }>
11
+ * Bytes (Buffer|ArrayBuffer|TypedArray) [single file]
12
+ * Bloby (Blob|File) [single file]
13
+ * String [single file]
14
+ * { path, content: Bytes } [single file]
15
+ * { path, content: Bloby } [single file]
16
+ * { path, content: String } [single file]
17
+ * { path, content: Iterable<Number> } [single file]
18
+ * { path, content: Iterable<Bytes> } [single file]
19
+ * { path, content: AsyncIterable<Bytes> } [single file]
20
+ * { path, content: PullStream<Bytes> } [single file]
21
+ * Iterable<Number> [single file]
22
+ * Iterable<Bytes> [single file]
23
+ * Iterable<Bloby> [multiple files]
24
+ * Iterable<String> [multiple files]
25
+ * Iterable<{ path, content: Bytes }> [multiple files]
26
+ * Iterable<{ path, content: Bloby }> [multiple files]
27
+ * Iterable<{ path, content: String }> [multiple files]
28
+ * Iterable<{ path, content: Iterable<Number> }> [multiple files]
29
+ * Iterable<{ path, content: Iterable<Bytes> }> [multiple files]
30
+ * Iterable<{ path, content: AsyncIterable<Bytes> }> [multiple files]
31
+ * Iterable<{ path, content: PullStream<Bytes> }> [multiple files]
32
+ * AsyncIterable<Bytes> [single file]
33
+ * AsyncIterable<Bloby> [multiple files]
34
+ * AsyncIterable<String> [multiple files]
35
+ * AsyncIterable<{ path, content: Bytes }> [multiple files]
36
+ * AsyncIterable<{ path, content: Bloby }> [multiple files]
37
+ * AsyncIterable<{ path, content: String }> [multiple files]
38
+ * AsyncIterable<{ path, content: Iterable<Number> }> [multiple files]
39
+ * AsyncIterable<{ path, content: Iterable<Bytes> }> [multiple files]
40
+ * AsyncIterable<{ path, content: AsyncIterable<Bytes> }> [multiple files]
41
+ * AsyncIterable<{ path, content: PullStream<Bytes> }> [multiple files]
42
+ * PullStream<Bytes> [single file]
43
+ * PullStream<Bloby> [multiple files]
44
+ * PullStream<String> [multiple files]
45
+ * PullStream<{ path, content: Bytes }> [multiple files]
46
+ * PullStream<{ path, content: Bloby }> [multiple files]
47
+ * PullStream<{ path, content: String }> [multiple files]
48
+ * PullStream<{ path, content: Iterable<Number> }> [multiple files]
49
+ * PullStream<{ path, content: Iterable<Bytes> }> [multiple files]
50
+ * PullStream<{ path, content: AsyncIterable<Bytes> }> [multiple files]
51
+ * PullStream<{ path, content: PullStream<Bytes> }> [multiple files]
31
52
* ```
32
53
* Into:
33
54
*
@@ -44,13 +65,6 @@ module.exports = function normaliseInput (input) {
44
65
throw errCode ( new Error ( `Unexpected input: ${ input } ` , 'ERR_UNEXPECTED_INPUT' ) )
45
66
}
46
67
47
- // { path, content: ? }
48
- if ( isFileObject ( input ) ) {
49
- return ( async function * ( ) { // eslint-disable-line require-await
50
- yield toFileObject ( input )
51
- } ) ( )
52
- }
53
-
54
68
// String
55
69
if ( typeof input === 'string' || input instanceof String ) {
56
70
return ( async function * ( ) { // eslint-disable-line require-await
@@ -68,76 +82,165 @@ module.exports = function normaliseInput (input) {
68
82
69
83
// Iterable<?>
70
84
if ( input [ Symbol . iterator ] ) {
71
- // Iterable<Number>
72
- if ( ! isNaN ( input [ 0 ] ) ) {
73
- return ( async function * ( ) { // eslint-disable-line require-await
74
- yield toFileObject ( [ input ] )
75
- } ) ( )
76
- }
77
-
78
- // Iterable<Buffer>
79
- // Iterable<Blob>
80
85
return ( async function * ( ) { // eslint-disable-line require-await
81
- for ( const chunk of input ) {
82
- yield toFileObject ( chunk )
86
+ const iterator = input [ Symbol . iterator ] ( )
87
+ const first = iterator . next ( )
88
+ if ( first . done ) return iterator
89
+
90
+ // Iterable<Number>
91
+ // Iterable<Bytes>
92
+ if ( Number . isInteger ( first . value ) || isBytes ( first . value ) ) {
93
+ yield toFileObject ( ( function * ( ) {
94
+ yield first . value
95
+ yield * iterator
96
+ } ) ( ) )
97
+ return
83
98
}
99
+
100
+ // Iterable<Bloby>
101
+ // Iterable<String>
102
+ // Iterable<{ path, content }>
103
+ if ( isFileObject ( first . value ) || isBloby ( first . value ) || typeof first . value === 'string' ) {
104
+ yield toFileObject ( first . value )
105
+ for ( const obj of iterator ) {
106
+ yield toFileObject ( obj )
107
+ }
108
+ return
109
+ }
110
+
111
+ throw errCode ( new Error ( 'Unexpected input: ' + typeof input ) , 'ERR_UNEXPECTED_INPUT' )
84
112
} ) ( )
85
113
}
86
114
87
115
// AsyncIterable<?>
88
116
if ( input [ Symbol . asyncIterator ] ) {
117
+ return ( async function * ( ) {
118
+ const iterator = input [ Symbol . asyncIterator ] ( )
119
+ const first = await iterator . next ( )
120
+ if ( first . done ) return iterator
121
+
122
+ // AsyncIterable<Bytes>
123
+ if ( isBytes ( first . value ) ) {
124
+ yield toFileObject ( ( async function * ( ) { // eslint-disable-line require-await
125
+ yield first . value
126
+ yield * iterator
127
+ } ) ( ) )
128
+ return
129
+ }
130
+
131
+ // AsyncIterable<Bloby>
132
+ // AsyncIterable<String>
133
+ // AsyncIterable<{ path, content }>
134
+ if ( isFileObject ( first . value ) || isBloby ( first . value ) || typeof first . value === 'string' ) {
135
+ yield toFileObject ( first . value )
136
+ for await ( const obj of iterator ) {
137
+ yield toFileObject ( obj )
138
+ }
139
+ return
140
+ }
141
+
142
+ throw errCode ( new Error ( 'Unexpected input: ' + typeof input ) , 'ERR_UNEXPECTED_INPUT' )
143
+ } ) ( )
144
+ }
145
+
146
+ // { path, content: ? }
147
+ // Note: Detected _after_ AsyncIterable<?> because Node.js streams have a
148
+ // `path` property that passes this check.
149
+ if ( isFileObject ( input ) ) {
89
150
return ( async function * ( ) { // eslint-disable-line require-await
90
- for await ( const chunk of input ) {
91
- yield toFileObject ( chunk )
151
+ yield toFileObject ( input )
152
+ } ) ( )
153
+ }
154
+
155
+ // PullStream<?>
156
+ if ( typeof input === 'function' ) {
157
+ return ( async function * ( ) {
158
+ const iterator = pullStreamToIterable ( input ) [ Symbol . asyncIterator ] ( )
159
+ const first = await iterator . next ( )
160
+ if ( first . done ) return iterator
161
+
162
+ // PullStream<Bytes>
163
+ if ( isBytes ( first . value ) ) {
164
+ yield toFileObject ( ( async function * ( ) { // eslint-disable-line require-await
165
+ yield first . value
166
+ yield * iterator
167
+ } ) ( ) )
168
+ return
169
+ }
170
+
171
+ // PullStream<Bloby>
172
+ // PullStream<String>
173
+ // PullStream<{ path, content }>
174
+ if ( isFileObject ( first . value ) || isBloby ( first . value ) || typeof first . value === 'string' ) {
175
+ yield toFileObject ( first . value )
176
+ for await ( const obj of iterator ) {
177
+ yield toFileObject ( obj )
178
+ }
179
+ return
92
180
}
181
+
182
+ throw errCode ( new Error ( 'Unexpected input: ' + typeof input ) , 'ERR_UNEXPECTED_INPUT' )
93
183
} ) ( )
94
184
}
95
185
96
186
throw errCode ( new Error ( 'Unexpected input: ' + typeof input ) , 'ERR_UNEXPECTED_INPUT' )
97
187
}
98
188
99
189
function toFileObject ( input ) {
100
- return {
101
- path : input . path || '' ,
102
- content : toAsyncIterable ( input . content || input )
190
+ const obj = { path : input . path || '' }
191
+
192
+ if ( input . content ) {
193
+ obj . content = toAsyncIterable ( input . content )
194
+ } else if ( ! input . path ) { // Not already a file object with path or content prop
195
+ obj . content = toAsyncIterable ( input )
103
196
}
197
+
198
+ return obj
104
199
}
105
200
106
201
function toAsyncIterable ( input ) {
107
- // Buffer|ArrayBuffer|TypedArray|array of bytes
108
- if ( isBytes ( input ) ) {
109
- return ( async function * ( ) { // eslint-disable-line require-await
110
- yield toBuffer ( input )
111
- } ) ( )
112
- }
113
-
114
- if ( typeof input === 'string' || input instanceof String ) {
202
+ // Bytes | String
203
+ if ( isBytes ( input ) || typeof input === 'string' ) {
115
204
return ( async function * ( ) { // eslint-disable-line require-await
116
205
yield toBuffer ( input )
117
206
} ) ( )
118
207
}
119
208
120
- // Blob|File
209
+ // Bloby
121
210
if ( isBloby ( input ) ) {
122
211
return blobToAsyncGenerator ( input )
123
212
}
124
213
125
214
// Iterator<?>
126
215
if ( input [ Symbol . iterator ] ) {
127
- if ( ! isNaN ( input [ 0 ] ) ) {
128
- return ( async function * ( ) { // eslint-disable-line require-await
129
- yield toBuffer ( input )
130
- } ) ( )
131
- }
132
-
133
216
return ( async function * ( ) { // eslint-disable-line require-await
134
- for ( const chunk of input ) {
135
- yield toBuffer ( chunk )
217
+ const iterator = input [ Symbol . iterator ] ( )
218
+ const first = iterator . next ( )
219
+ if ( first . done ) return iterator
220
+
221
+ // Iterable<Number>
222
+ if ( Number . isInteger ( first . value ) ) {
223
+ yield toBuffer ( Array . from ( ( function * ( ) {
224
+ yield first . value
225
+ yield * iterator
226
+ } ) ( ) ) )
227
+ return
228
+ }
229
+
230
+ // Iterable<Bytes>
231
+ if ( isBytes ( first . value ) ) {
232
+ yield toBuffer ( first . value )
233
+ for ( const chunk of iterator ) {
234
+ yield toBuffer ( chunk )
235
+ }
236
+ return
136
237
}
238
+
239
+ throw errCode ( new Error ( 'Unexpected input: ' + typeof input ) , 'ERR_UNEXPECTED_INPUT' )
137
240
} ) ( )
138
241
}
139
242
140
- // AsyncIterable<? >
243
+ // AsyncIterable<Bytes >
141
244
if ( input [ Symbol . asyncIterator ] ) {
142
245
return ( async function * ( ) {
143
246
for await ( const chunk of input ) {
@@ -146,23 +249,16 @@ function toAsyncIterable (input) {
146
249
} ) ( )
147
250
}
148
251
252
+ // PullStream<Bytes>
253
+ if ( typeof input === 'function' ) {
254
+ return pullStreamToIterable ( input )
255
+ }
256
+
149
257
throw errCode ( new Error ( `Unexpected input: ${ input } ` , 'ERR_UNEXPECTED_INPUT' ) )
150
258
}
151
259
152
260
function toBuffer ( chunk ) {
153
- if ( isBytes ( chunk ) ) {
154
- return chunk
155
- }
156
-
157
- if ( typeof chunk === 'string' || chunk instanceof String ) {
158
- return Buffer . from ( chunk )
159
- }
160
-
161
- if ( Array . isArray ( chunk ) ) {
162
- return Buffer . from ( chunk )
163
- }
164
-
165
- throw new Error ( 'Unexpected input: ' + typeof chunk )
261
+ return isBytes ( chunk ) ? chunk : Buffer . from ( chunk )
166
262
}
167
263
168
264
function isBytes ( obj ) {
0 commit comments