Skip to content

Commit 5d7510a

Browse files
committed
refactor: remove concat-stream dependency and modernize MemoryStorage
Replace external concat-stream with a simplified custom implementation without additional deps and convert to ES6 classes
1 parent b6e4b1f commit 5d7510a

File tree

2 files changed

+84
-14
lines changed

2 files changed

+84
-14
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@
2525
"dependencies": {
2626
"append-field": "^1.0.0",
2727
"busboy": "^1.6.0",
28-
"concat-stream": "^2.0.0",
2928
"type-is": "^1.6.18"
3029
},
3130
"devDependencies": {
31+
"concat-stream": "^2.0.0",
3232
"deep-equal": "^2.0.3",
3333
"express": "^4.21.2",
3434
"form-data": "^4.0.2",

storage/memory.js

Lines changed: 83 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,91 @@
1-
var concat = require('concat-stream')
1+
const Writable = require('stream').Writable
2+
const Buffer = require('buffer').Buffer
3+
const isUint8Array = require('util').types.isUint8Array
24

3-
function MemoryStorage (opts) {}
5+
class MemoryStorage {
6+
_handleFile (req, file, cb) {
7+
file.stream.pipe(
8+
new ConcatStream(function (data) {
9+
cb(null, {
10+
buffer: data,
11+
size: data.length
12+
})
13+
})
14+
)
15+
}
416

5-
MemoryStorage.prototype._handleFile = function _handleFile (req, file, cb) {
6-
file.stream.pipe(concat({ encoding: 'buffer' }, function (data) {
7-
cb(null, {
8-
buffer: data,
9-
size: data.length
17+
_removeFile (req, file, cb) {
18+
delete file.buffer
19+
cb(null)
20+
}
21+
}
22+
23+
module.exports = function () {
24+
return new MemoryStorage()
25+
}
26+
27+
/**
28+
* Writable stream that concatenates all written chunks into a single Buffer.
29+
*
30+
* Implementation inspired by the concat-stream npm package (https://www.npmjs.com/package/concat-stream),
31+
* modified for our specific use case.
32+
*/
33+
class ConcatStream extends Writable {
34+
/**
35+
* Creates a new ConcatStream instance.
36+
* @param {function(Buffer): void} cb - Callback invoked with the concatenated Buffer when the stream finishes.
37+
*/
38+
constructor (cb) {
39+
super()
40+
this.body = []
41+
this.on('finish', function () {
42+
cb(this.getBody())
1043
})
11-
}))
44+
}
45+
46+
_write (chunk, enc, next) {
47+
this.body.push(chunk)
48+
next()
49+
}
50+
51+
/**
52+
* Concatenates all collected chunks into a single Buffer.
53+
* @returns {Buffer} The concatenated buffer containing all written data.
54+
*/
55+
getBody () {
56+
const bufs = []
57+
for (const p of this.body) {
58+
// Buffer.concat can handle Buffer and Uint8Array (and subclasses)
59+
if (Buffer.isBuffer(p) || isUint8Array(p)) {
60+
bufs.push(p)
61+
} else if (isBufferish(p)) {
62+
bufs.push(Buffer.from(p))
63+
} else {
64+
bufs.push(Buffer.from(String(p)))
65+
}
66+
}
67+
return Buffer.concat(bufs)
68+
}
1269
}
1370

14-
MemoryStorage.prototype._removeFile = function _removeFile (req, file, cb) {
15-
delete file.buffer
16-
cb(null)
71+
/**
72+
* Checks if the given value is array-like.
73+
* @param {*} arr
74+
* @returns {boolean}
75+
*/
76+
function isArrayish (arr) {
77+
return /Array\]$/.test(Object.prototype.toString.call(arr))
1778
}
1879

19-
module.exports = function (opts) {
20-
return new MemoryStorage(opts)
80+
/**
81+
* Checks if the given value is Buffer-like.
82+
* @param {*} p
83+
* @returns {boolean}
84+
*/
85+
function isBufferish (p) {
86+
return (
87+
typeof p === 'string' ||
88+
isArrayish(p) ||
89+
(p && typeof p.subarray === 'function')
90+
)
2191
}

0 commit comments

Comments
 (0)