mirror of
https://github.com/nodejs/node.git
synced 2025-05-03 22:25:44 +00:00

PR-URL: https://github.com/nodejs/node/pull/50408 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Raz Luvaton <rluvaton@gmail.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
365 lines
8.7 KiB
JavaScript
365 lines
8.7 KiB
JavaScript
'use strict';
|
|
|
|
const {
|
|
SymbolAsyncIterator,
|
|
SymbolIterator,
|
|
SymbolFor,
|
|
Symbol,
|
|
} = primordials;
|
|
|
|
// We need to use SymbolFor to make these globally available
|
|
// for interopt with readable-stream, i.e. readable-stream
|
|
// and node core needs to be able to read/write private state
|
|
// from each other for proper interoperability.
|
|
const kIsDestroyed = SymbolFor('nodejs.stream.destroyed');
|
|
const kIsErrored = SymbolFor('nodejs.stream.errored');
|
|
const kIsReadable = SymbolFor('nodejs.stream.readable');
|
|
const kIsWritable = SymbolFor('nodejs.stream.writable');
|
|
const kIsDisturbed = SymbolFor('nodejs.stream.disturbed');
|
|
|
|
const kOnConstructed = Symbol('kOnConstructed');
|
|
|
|
const kIsClosedPromise = SymbolFor('nodejs.webstream.isClosedPromise');
|
|
const kControllerErrorFunction = SymbolFor('nodejs.webstream.controllerErrorFunction');
|
|
|
|
const kState = Symbol('kState');
|
|
const kObjectMode = 1 << 0;
|
|
const kErrorEmitted = 1 << 1;
|
|
const kAutoDestroy = 1 << 2;
|
|
const kEmitClose = 1 << 3;
|
|
const kDestroyed = 1 << 4;
|
|
const kClosed = 1 << 5;
|
|
const kCloseEmitted = 1 << 6;
|
|
const kErrored = 1 << 7;
|
|
const kConstructed = 1 << 8;
|
|
|
|
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 isReadableStream(obj) {
|
|
return !!(
|
|
obj &&
|
|
!isNodeStream(obj) &&
|
|
typeof obj.pipeThrough === 'function' &&
|
|
typeof obj.getReader === 'function' &&
|
|
typeof obj.cancel === 'function'
|
|
);
|
|
}
|
|
|
|
function isWritableStream(obj) {
|
|
return !!(
|
|
obj &&
|
|
!isNodeStream(obj) &&
|
|
typeof obj.getWriter === 'function' &&
|
|
typeof obj.abort === 'function'
|
|
);
|
|
}
|
|
|
|
function isTransformStream(obj) {
|
|
return !!(
|
|
obj &&
|
|
!isNodeStream(obj) &&
|
|
typeof obj.readable === 'object' &&
|
|
typeof obj.writable === 'object'
|
|
);
|
|
}
|
|
|
|
function isWebStream(obj) {
|
|
return isReadableStream(obj) || isWritableStream(obj) || isTransformStream(obj);
|
|
}
|
|
|
|
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[kIsDestroyed] || 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 (stream && stream[kIsWritable] != null) return stream[kIsWritable];
|
|
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 = {
|
|
kOnConstructed,
|
|
isDestroyed,
|
|
kIsDestroyed,
|
|
isDisturbed,
|
|
kIsDisturbed,
|
|
isErrored,
|
|
kIsErrored,
|
|
isReadable,
|
|
kIsReadable,
|
|
kIsClosedPromise,
|
|
kControllerErrorFunction,
|
|
kIsWritable,
|
|
isClosed,
|
|
isDuplexNodeStream,
|
|
isFinished,
|
|
isIterable,
|
|
isReadableNodeStream,
|
|
isReadableStream,
|
|
isReadableEnded,
|
|
isReadableFinished,
|
|
isReadableErrored,
|
|
isNodeStream,
|
|
isWebStream,
|
|
isWritable,
|
|
isWritableNodeStream,
|
|
isWritableStream,
|
|
isWritableEnded,
|
|
isWritableFinished,
|
|
isWritableErrored,
|
|
isServerRequest,
|
|
isServerResponse,
|
|
willEmitClose,
|
|
isTransformStream,
|
|
kState,
|
|
// bitfields
|
|
kObjectMode,
|
|
kErrorEmitted,
|
|
kAutoDestroy,
|
|
kEmitClose,
|
|
kDestroyed,
|
|
kClosed,
|
|
kCloseEmitted,
|
|
kErrored,
|
|
kConstructed,
|
|
};
|