Skip to content

Commit a9f8b62

Browse files
ronagtargos
authored andcommitted
stream: add readableEnded
Adds a readableEnded property and improved finished compat with possible stream-like objects. PR-URL: #28814 Refs: #28813 Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: Rich Trott <[email protected]>
1 parent f42eb01 commit a9f8b62

File tree

6 files changed

+64
-2
lines changed

6 files changed

+64
-2
lines changed

doc/api/stream.md

+9
Original file line numberDiff line numberDiff line change
@@ -1126,6 +1126,15 @@ added: v12.7.0
11261126
Getter for the property `encoding` of a given `Readable` stream. The `encoding`
11271127
property can be set using the [`readable.setEncoding()`][] method.
11281128

1129+
##### readable.readableEnded
1130+
<!-- YAML
1131+
added: REPLACEME
1132+
-->
1133+
1134+
* {boolean}
1135+
1136+
Becomes `true` when [`'end'`][] event is emitted.
1137+
11291138
##### readable.readableHighWaterMark
11301139
<!-- YAML
11311140
added: v9.3.0

lib/_stream_readable.js

+10
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,16 @@ Object.defineProperty(Readable.prototype, 'destroyed', {
196196
}
197197
});
198198

199+
Object.defineProperty(Readable.prototype, 'readableEnded', {
200+
// Making it explicit this property is not enumerable
201+
// because otherwise some prototype manipulation in
202+
// userland will fail
203+
enumerable: false,
204+
get() {
205+
return this._readableState ? this._readableState.endEmitted : false;
206+
}
207+
});
208+
199209
Readable.prototype.destroy = destroyImpl.destroy;
200210
Readable.prototype._undestroy = destroyImpl.undestroy;
201211
Readable.prototype._destroy = function(err, cb) {

lib/internal/streams/async_iterator.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ const createReadableStreamAsyncIterator = (stream) => {
132132
[kLastReject]: { value: null, writable: true },
133133
[kError]: { value: null, writable: true },
134134
[kEnded]: {
135-
value: stream._readableState.endEmitted,
135+
value: stream.readableEnded || stream._readableState.endEmitted,
136136
writable: true
137137
},
138138
// The function passed to new Promise is cached so we avoid allocating a new

lib/internal/streams/end-of-stream.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ function eos(stream, opts, callback) {
4242
if (!readable) callback.call(stream);
4343
};
4444

45-
var readableEnded = stream._readableState && stream._readableState.endEmitted;
45+
var readableEnded = stream.readableEnded ||
46+
(stream._readableState && stream._readableState.endEmitted);
4647
const onend = () => {
4748
readable = false;
4849
readableEnded = true;

test/parallel/test-stream-finished.js

+9
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
const common = require('../common');
44
const { Writable, Readable, Transform, finished } = require('stream');
55
const assert = require('assert');
6+
const EE = require('events');
67
const fs = require('fs');
78
const { promisify } = require('util');
89

@@ -175,3 +176,11 @@ const { promisify } = require('util');
175176
rs.push(null);
176177
rs.resume();
177178
}
179+
180+
{
181+
const streamLike = new EE();
182+
streamLike.readableEnded = true;
183+
streamLike.readable = true;
184+
finished(streamLike, common.mustCall);
185+
streamLike.emit('close');
186+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const { Readable } = require('stream');
5+
const assert = require('assert');
6+
7+
// basic
8+
{
9+
// Find it on Readable.prototype
10+
assert(Readable.prototype.hasOwnProperty('readableEnded'));
11+
}
12+
13+
// event
14+
{
15+
const readable = new Readable();
16+
17+
readable._read = () => {
18+
// The state ended should start in false.
19+
assert.strictEqual(readable.readableEnded, false);
20+
readable.push('asd');
21+
assert.strictEqual(readable.readableEnded, false);
22+
readable.push(null);
23+
assert.strictEqual(readable.readableEnded, false);
24+
};
25+
26+
readable.on('end', common.mustCall(() => {
27+
assert.strictEqual(readable.readableEnded, true);
28+
}));
29+
30+
readable.on('data', common.mustCall(() => {
31+
assert.strictEqual(readable.readableEnded, false);
32+
}));
33+
}

0 commit comments

Comments
 (0)