Skip to content

Commit ae307ff

Browse files
committed
make buffer and pipes properties actually private
BREAKING CHANGE: this removes .buffer and .pipes from the publicly exposed interface, allowing Minipass to be safely used as a base class for exported TypeScript mixins.
1 parent 52ab642 commit ae307ff

File tree

4 files changed

+41
-41
lines changed

4 files changed

+41
-41
lines changed

index.d.ts

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
/// <reference types="node" />
2+
3+
// Note: marking anything protected or private in the exported
4+
// class will limit Minipass's ability to be used as the base
5+
// for mixin classes.
26
import { EventEmitter } from 'events'
37
import { Stream } from 'stream'
48

@@ -16,12 +20,6 @@ declare namespace Minipass {
1620
pipe(): any
1721
}
1822

19-
interface Pipe<R, W> {
20-
src: Minipass<R, W>
21-
dest: Writable
22-
opts: PipeOptions
23-
}
24-
2523
type DualIterable<T> = Iterable<T> & AsyncIterable<T>
2624

2725
type ContiguousData = Buffer | ArrayBufferLike | ArrayBufferView | string
@@ -76,12 +74,6 @@ declare class Minipass<
7674
readonly emittedEnd: boolean
7775
readonly destroyed: boolean
7876

79-
/**
80-
* Not technically private or readonly, but not safe to mutate.
81-
*/
82-
private readonly buffer: RType[]
83-
private readonly pipes: Minipass.Pipe<RType, WType>[]
84-
8577
/**
8678
* Technically writable, but mutating it can change the type,
8779
* so is not safe to do in TypeScript.

index.js

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ const DECODER = Symbol('decoder')
2121
const FLOWING = Symbol('flowing')
2222
const PAUSED = Symbol('paused')
2323
const RESUME = Symbol('resume')
24+
const BUFFER = Symbol('buffer')
25+
const PIPES = Symbol('pipes')
2426
const BUFFERLENGTH = Symbol('bufferLength')
2527
const BUFFERPUSH = Symbol('bufferPush')
2628
const BUFFERSHIFT = Symbol('bufferShift')
@@ -94,8 +96,8 @@ module.exports = class Minipass extends Stream {
9496
this[FLOWING] = false
9597
// whether we're explicitly paused
9698
this[PAUSED] = false
97-
this.pipes = []
98-
this.buffer = []
99+
this[PIPES] = []
100+
this[BUFFER] = []
99101
this[OBJECTMODE] = options && options.objectMode || false
100102
if (this[OBJECTMODE])
101103
this[ENCODING] = null
@@ -114,6 +116,12 @@ module.exports = class Minipass extends Stream {
114116
this.readable = true
115117
this[BUFFERLENGTH] = 0
116118
this[DESTROYED] = false
119+
if (options && options.debugExposeBuffer === true) {
120+
Object.defineProperty(this, 'buffer', { get: () => this[BUFFER] })
121+
}
122+
if (options && options.debugExposePipes === true) {
123+
Object.defineProperty(this, 'pipes', { get: () => this[PIPES] })
124+
}
117125
}
118126

119127
get bufferLength () { return this[BUFFERLENGTH] }
@@ -129,8 +137,8 @@ module.exports = class Minipass extends Stream {
129137

130138
if (this[ENCODING] !== enc) {
131139
this[DECODER] = enc ? new SD(enc) : null
132-
if (this.buffer.length)
133-
this.buffer = this.buffer.map(chunk => this[DECODER].write(chunk))
140+
if (this[BUFFER].length)
141+
this[BUFFER] = this[BUFFER].map(chunk => this[DECODER].write(chunk))
134142
}
135143

136144
this[ENCODING] = enc
@@ -252,14 +260,14 @@ module.exports = class Minipass extends Stream {
252260
if (this[OBJECTMODE])
253261
n = null
254262

255-
if (this.buffer.length > 1 && !this[OBJECTMODE]) {
263+
if (this[BUFFER].length > 1 && !this[OBJECTMODE]) {
256264
if (this.encoding)
257-
this.buffer = [this.buffer.join('')]
265+
this[BUFFER] = [this[BUFFER].join('')]
258266
else
259-
this.buffer = [Buffer.concat(this.buffer, this[BUFFERLENGTH])]
267+
this[BUFFER] = [Buffer.concat(this[BUFFER], this[BUFFERLENGTH])]
260268
}
261269

262-
const ret = this[READ](n || null, this.buffer[0])
270+
const ret = this[READ](n || null, this[BUFFER][0])
263271
this[MAYBE_EMIT_END]()
264272
return ret
265273
}
@@ -268,14 +276,14 @@ module.exports = class Minipass extends Stream {
268276
if (n === chunk.length || n === null)
269277
this[BUFFERSHIFT]()
270278
else {
271-
this.buffer[0] = chunk.slice(n)
279+
this[BUFFER][0] = chunk.slice(n)
272280
chunk = chunk.slice(0, n)
273281
this[BUFFERLENGTH] -= n
274282
}
275283

276284
this.emit('data', chunk)
277285

278-
if (!this.buffer.length && !this[EOF])
286+
if (!this[BUFFER].length && !this[EOF])
279287
this.emit('drain')
280288

281289
return chunk
@@ -310,7 +318,7 @@ module.exports = class Minipass extends Stream {
310318
this[PAUSED] = false
311319
this[FLOWING] = true
312320
this.emit('resume')
313-
if (this.buffer.length)
321+
if (this[BUFFER].length)
314322
this[FLUSH]()
315323
else if (this[EOF])
316324
this[MAYBE_EMIT_END]()
@@ -344,23 +352,23 @@ module.exports = class Minipass extends Stream {
344352
this[BUFFERLENGTH] += 1
345353
else
346354
this[BUFFERLENGTH] += chunk.length
347-
this.buffer.push(chunk)
355+
this[BUFFER].push(chunk)
348356
}
349357

350358
[BUFFERSHIFT] () {
351-
if (this.buffer.length) {
359+
if (this[BUFFER].length) {
352360
if (this[OBJECTMODE])
353361
this[BUFFERLENGTH] -= 1
354362
else
355-
this[BUFFERLENGTH] -= this.buffer[0].length
363+
this[BUFFERLENGTH] -= this[BUFFER][0].length
356364
}
357-
return this.buffer.shift()
365+
return this[BUFFER].shift()
358366
}
359367

360368
[FLUSH] (noDrain) {
361369
do {} while (this[FLUSHCHUNK](this[BUFFERSHIFT]()))
362370

363-
if (!noDrain && !this.buffer.length && !this[EOF])
371+
if (!noDrain && !this[BUFFER].length && !this[EOF])
364372
this.emit('drain')
365373
}
366374

@@ -385,7 +393,7 @@ module.exports = class Minipass extends Stream {
385393
if (opts.end)
386394
dest.end()
387395
} else {
388-
this.pipes.push(!opts.proxyErrors ? new Pipe(this, dest, opts)
396+
this[PIPES].push(!opts.proxyErrors ? new Pipe(this, dest, opts)
389397
: new PipeProxyErrors(this, dest, opts))
390398
if (this[ASYNC])
391399
defer(() => this[RESUME]())
@@ -397,9 +405,9 @@ module.exports = class Minipass extends Stream {
397405
}
398406

399407
unpipe (dest) {
400-
const p = this.pipes.find(p => p.dest === dest)
408+
const p = this[PIPES].find(p => p.dest === dest)
401409
if (p) {
402-
this.pipes.splice(this.pipes.indexOf(p), 1)
410+
this[PIPES].splice(this[PIPES].indexOf(p), 1)
403411
p.unpipe()
404412
}
405413
}
@@ -410,7 +418,7 @@ module.exports = class Minipass extends Stream {
410418

411419
on (ev, fn) {
412420
const ret = super.on(ev, fn)
413-
if (ev === 'data' && !this.pipes.length && !this.flowing)
421+
if (ev === 'data' && !this[PIPES].length && !this.flowing)
414422
this[RESUME]()
415423
else if (ev === 'readable' && this[BUFFERLENGTH] !== 0)
416424
super.emit('readable')
@@ -434,7 +442,7 @@ module.exports = class Minipass extends Stream {
434442
if (!this[EMITTING_END] &&
435443
!this[EMITTED_END] &&
436444
!this[DESTROYED] &&
437-
this.buffer.length === 0 &&
445+
this[BUFFER].length === 0 &&
438446
this[EOF]) {
439447
this[EMITTING_END] = true
440448
this.emit('end')
@@ -486,7 +494,7 @@ module.exports = class Minipass extends Stream {
486494
}
487495

488496
[EMITDATA] (data) {
489-
for (const p of this.pipes) {
497+
for (const p of this[PIPES]) {
490498
if (p.dest.write(data) === false)
491499
this.pause()
492500
}
@@ -511,14 +519,14 @@ module.exports = class Minipass extends Stream {
511519
if (this[DECODER]) {
512520
const data = this[DECODER].end()
513521
if (data) {
514-
for (const p of this.pipes) {
522+
for (const p of this[PIPES]) {
515523
p.dest.write(data)
516524
}
517525
super.emit('data', data)
518526
}
519527
}
520528

521-
for (const p of this.pipes) {
529+
for (const p of this[PIPES]) {
522530
p.end()
523531
}
524532
const ret = super.emit('end')
@@ -625,7 +633,7 @@ module.exports = class Minipass extends Stream {
625633
this[DESTROYED] = true
626634

627635
// throw away all buffered data, it's never coming out
628-
this.buffer.length = 0
636+
this[BUFFER].length = 0
629637
this[BUFFERLENGTH] = 0
630638

631639
if (typeof this.close === 'function' && !this[CLOSED])

test/basic.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ const t = require('tap')
33
const EE = require('events').EventEmitter
44

55
t.test('some basic piping and writing', async t => {
6-
let mp = new MiniPass({ encoding: 'base64' })
6+
let mp = new MiniPass({ encoding: 'base64', debugExposeBuffer: true })
77
t.notOk(mp.flowing)
88
mp.flowing = true
99
t.notOk(mp.flowing)
@@ -13,7 +13,7 @@ t.test('some basic piping and writing', async t => {
1313
t.equal(mp.readable, true)
1414
t.equal(mp.writable, true)
1515
t.equal(mp.write('hello'), false)
16-
let dest = new MiniPass()
16+
let dest = new MiniPass({ debugExposeBuffer: true })
1717
let sawDestData = false
1818
dest.once('data', chunk => {
1919
sawDestData = true
@@ -279,7 +279,7 @@ t.test('emit works with many args', t => {
279279
})
280280

281281
t.test('emit drain on resume, even if no flush', t => {
282-
const mp = new MiniPass()
282+
const mp = new MiniPass({ debugExposeBuffer: true })
283283
mp.encoding = 'utf8'
284284

285285
const chunks = []

test/unpipe.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
const t = require('tap')
22
const Minipass = require('../')
33

4-
const src = new Minipass({ encoding: 'utf8' })
4+
const src = new Minipass({ encoding: 'utf8', debugExposePipes: true })
55
const dest = new Minipass({ encoding: 'utf8' })
66
const dest2 = new Minipass({ encoding: 'utf8' })
77
const destOut = []

0 commit comments

Comments
 (0)