'use strict'; const { Symbol, SymbolAsyncIterator, SymbolIterator, } = primordials; const kDestroyed = Symbol('kDestroyed'); const kIsErrored = Symbol('kIsErrored'); const kIsReadable = Symbol('kIsReadable'); const kIsDisturbed = Symbol('kIsDisturbed'); function isReadableNodeStream(obj, strict = false) { return !!( obj && typeof obj.pipe === 'function' && typeof obj.on === 'function' && ( !strict || (typeof obj.pause === 'function' && typeof obj.resume === 'function') ) && (!obj._writableState || obj._readableState?.readable !== false) && // Duplex (!obj._writableState || obj._readableState) // Writable has .pipe. ); } function isWritableNodeStream(obj) { return !!( obj && typeof obj.write === 'function' && typeof obj.on === 'function' && (!obj._readableState || obj._writableState?.writable !== false) // Duplex ); } function isDuplexNodeStream(obj) { return !!( obj && (typeof obj.pipe === 'function' && obj._readableState) && typeof obj.on === 'function' && typeof obj.write === 'function' ); } function isNodeStream(obj) { return ( obj && ( obj._readableState || obj._writableState || (typeof obj.write === 'function' && typeof obj.on === 'function') || (typeof obj.pipe === 'function' && typeof obj.on === 'function') ) ); } function isIterable(obj, isAsync) { if (obj == null) return false; if (isAsync === true) return typeof obj[SymbolAsyncIterator] === 'function'; if (isAsync === false) return typeof obj[SymbolIterator] === 'function'; return typeof obj[SymbolAsyncIterator] === 'function' || typeof obj[SymbolIterator] === 'function'; } function isDestroyed(stream) { if (!isNodeStream(stream)) return null; const wState = stream._writableState; const rState = stream._readableState; const state = wState || rState; return !!(stream.destroyed || stream[kDestroyed] || state?.destroyed); } // Have been end():d. function isWritableEnded(stream) { if (!isWritableNodeStream(stream)) return null; if (stream.writableEnded === true) return true; const wState = stream._writableState; if (wState?.errored) return false; if (typeof wState?.ended !== 'boolean') return null; return wState.ended; } // Have emitted 'finish'. function isWritableFinished(stream, strict) { if (!isWritableNodeStream(stream)) return null; if (stream.writableFinished === true) return true; const wState = stream._writableState; if (wState?.errored) return false; if (typeof wState?.finished !== 'boolean') return null; return !!( wState.finished || (strict === false && wState.ended === true && wState.length === 0) ); } // Have been push(null):d. function isReadableEnded(stream) { if (!isReadableNodeStream(stream)) return null; if (stream.readableEnded === true) return true; const rState = stream._readableState; if (!rState || rState.errored) return false; if (typeof rState?.ended !== 'boolean') return null; return rState.ended; } // Have emitted 'end'. function isReadableFinished(stream, strict) { if (!isReadableNodeStream(stream)) return null; const rState = stream._readableState; if (rState?.errored) return false; if (typeof rState?.endEmitted !== 'boolean') return null; return !!( rState.endEmitted || (strict === false && rState.ended === true && rState.length === 0) ); } function isReadable(stream) { if (stream && stream[kIsReadable] != null) return stream[kIsReadable]; if (typeof stream?.readable !== 'boolean') return null; if (isDestroyed(stream)) return false; return isReadableNodeStream(stream) && stream.readable && !isReadableFinished(stream); } function isWritable(stream) { if (typeof stream?.writable !== 'boolean') return null; if (isDestroyed(stream)) return false; return isWritableNodeStream(stream) && stream.writable && !isWritableEnded(stream); } function isFinished(stream, opts) { if (!isNodeStream(stream)) { return null; } if (isDestroyed(stream)) { return true; } if (opts?.readable !== false && isReadable(stream)) { return false; } if (opts?.writable !== false && isWritable(stream)) { return false; } return true; } function isWritableErrored(stream) { if (!isNodeStream(stream)) { return null; } if (stream.writableErrored) { return stream.writableErrored; } return stream._writableState?.errored ?? null; } function isReadableErrored(stream) { if (!isNodeStream(stream)) { return null; } if (stream.readableErrored) { return stream.readableErrored; } return stream._readableState?.errored ?? null; } function isClosed(stream) { if (!isNodeStream(stream)) { return null; } if (typeof stream.closed === 'boolean') { return stream.closed; } const wState = stream._writableState; const rState = stream._readableState; if ( typeof wState?.closed === 'boolean' || typeof rState?.closed === 'boolean' ) { return wState?.closed || rState?.closed; } if (typeof stream._closed === 'boolean' && isOutgoingMessage(stream)) { return stream._closed; } return null; } function isOutgoingMessage(stream) { return ( typeof stream._closed === 'boolean' && typeof stream._defaultKeepAlive === 'boolean' && typeof stream._removedConnection === 'boolean' && typeof stream._removedContLen === 'boolean' ); } function isServerResponse(stream) { return ( typeof stream._sent100 === 'boolean' && isOutgoingMessage(stream) ); } function isServerRequest(stream) { return ( typeof stream._consuming === 'boolean' && typeof stream._dumped === 'boolean' && stream.req?.upgradeOrConnect === undefined ); } function willEmitClose(stream) { if (!isNodeStream(stream)) return null; const wState = stream._writableState; const rState = stream._readableState; const state = wState || rState; return (!state && isServerResponse(stream)) || !!( state && state.autoDestroy && state.emitClose && state.closed === false ); } function isDisturbed(stream) { return !!(stream && ( stream[kIsDisturbed] ?? (stream.readableDidRead || stream.readableAborted) )); } function isErrored(stream) { return !!(stream && ( stream[kIsErrored] ?? stream.readableErrored ?? stream.writableErrored ?? stream._readableState?.errorEmitted ?? stream._writableState?.errorEmitted ?? stream._readableState?.errored ?? stream._writableState?.errored )); } module.exports = { kDestroyed, isDisturbed, kIsDisturbed, isErrored, kIsErrored, isReadable, kIsReadable, isClosed, isDestroyed, isDuplexNodeStream, isFinished, isIterable, isReadableNodeStream, isReadableEnded, isReadableFinished, isReadableErrored, isNodeStream, isWritable, isWritableNodeStream, isWritableEnded, isWritableFinished, isWritableErrored, isServerRequest, isServerResponse, willEmitClose, };