1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-26 00:59:24 -05:00
denoland-deno/cli/js/web/streams/readable_stream.ts
2020-07-14 15:24:17 -04:00

224 lines
6.9 KiB
TypeScript

// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import {
acquireReadableStreamDefaultReader,
initializeReadableStream,
isReadableStream,
isReadableStreamLocked,
isUnderlyingByteSource,
isWritableStream,
isWritableStreamLocked,
makeSizeAlgorithmFromSizeFunction,
setPromiseIsHandledToTrue,
readableStreamCancel,
ReadableStreamGenericReader,
readableStreamPipeTo,
readableStreamTee,
setUpReadableByteStreamControllerFromUnderlyingSource,
setUpReadableStreamDefaultControllerFromUnderlyingSource,
validateAndNormalizeHighWaterMark,
} from "./internals.ts";
import type { ReadableByteStreamControllerImpl } from "./readable_byte_stream_controller.ts";
import { ReadableStreamAsyncIteratorPrototype } from "./readable_stream_async_iterator.ts";
import type { ReadableStreamDefaultControllerImpl } from "./readable_stream_default_controller.ts";
import * as sym from "./symbols.ts";
import { customInspect } from "../console.ts";
import { AbortSignalImpl } from "../abort_signal.ts";
import { setFunctionName } from "../util.ts";
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export class ReadableStreamImpl<R = any> implements ReadableStream<R> {
[sym.disturbed]: boolean;
[sym.readableStreamController]:
| ReadableStreamDefaultControllerImpl<R>
| ReadableByteStreamControllerImpl;
[sym.reader]: ReadableStreamGenericReader<R> | undefined;
[sym.state]: "readable" | "closed" | "errored";
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[sym.storedError]: any;
constructor(
underlyingSource: UnderlyingByteSource | UnderlyingSource<R> = {},
strategy:
| {
highWaterMark?: number;
size?: undefined;
}
| QueuingStrategy<R> = {},
) {
initializeReadableStream(this);
const { size } = strategy;
let { highWaterMark } = strategy;
const { type } = underlyingSource;
if (isUnderlyingByteSource(underlyingSource)) {
if (size !== undefined) {
throw new RangeError(
`When underlying source is "bytes", strategy.size must be undefined.`,
);
}
highWaterMark = validateAndNormalizeHighWaterMark(highWaterMark ?? 0);
setUpReadableByteStreamControllerFromUnderlyingSource(
this,
underlyingSource,
highWaterMark,
);
} else if (type === undefined) {
const sizeAlgorithm = makeSizeAlgorithmFromSizeFunction(size);
highWaterMark = validateAndNormalizeHighWaterMark(highWaterMark ?? 1);
setUpReadableStreamDefaultControllerFromUnderlyingSource(
this,
underlyingSource,
highWaterMark,
sizeAlgorithm,
);
} else {
throw new RangeError(
`Valid values for underlyingSource are "bytes" or undefined. Received: "${type}".`,
);
}
}
get locked(): boolean {
if (!isReadableStream(this)) {
throw new TypeError("Invalid ReadableStream.");
}
return isReadableStreamLocked(this);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
cancel(reason?: any): Promise<void> {
if (!isReadableStream(this)) {
return Promise.reject(new TypeError("Invalid ReadableStream."));
}
if (isReadableStreamLocked(this)) {
return Promise.reject(
new TypeError("Cannot cancel a locked ReadableStream."),
);
}
return readableStreamCancel(this, reason);
}
getIterator({
preventCancel,
}: { preventCancel?: boolean } = {}): AsyncIterableIterator<R> {
if (!isReadableStream(this)) {
throw new TypeError("Invalid ReadableStream.");
}
const reader = acquireReadableStreamDefaultReader(this);
const iterator = Object.create(ReadableStreamAsyncIteratorPrototype);
iterator[sym.asyncIteratorReader] = reader;
iterator[sym.preventCancel] = Boolean(preventCancel);
return iterator;
}
getReader({ mode }: { mode?: string } = {}): ReadableStreamDefaultReader<R> {
if (!isReadableStream(this)) {
throw new TypeError("Invalid ReadableStream.");
}
if (mode === undefined) {
return acquireReadableStreamDefaultReader(this, true);
}
mode = String(mode);
// 3.2.5.4.4 If mode is "byob", return ? AcquireReadableStreamBYOBReader(this, true).
throw new RangeError(`Unsupported mode "${mode}"`);
}
pipeThrough<T>(
{
writable,
readable,
}: {
writable: WritableStream<R>;
readable: ReadableStream<T>;
},
{ preventClose, preventAbort, preventCancel, signal }: PipeOptions = {},
): ReadableStream<T> {
if (!isReadableStream(this)) {
throw new TypeError("Invalid ReadableStream.");
}
if (!isWritableStream(writable)) {
throw new TypeError("writable is not a valid WritableStream.");
}
if (!isReadableStream(readable)) {
throw new TypeError("readable is not a valid ReadableStream.");
}
preventClose = Boolean(preventClose);
preventAbort = Boolean(preventAbort);
preventCancel = Boolean(preventCancel);
if (signal && !(signal instanceof AbortSignalImpl)) {
throw new TypeError("Invalid signal.");
}
if (isReadableStreamLocked(this)) {
throw new TypeError("ReadableStream is locked.");
}
if (isWritableStreamLocked(writable)) {
throw new TypeError("writable is locked.");
}
const promise = readableStreamPipeTo(
this,
writable,
preventClose,
preventAbort,
preventCancel,
signal,
);
setPromiseIsHandledToTrue(promise);
return readable;
}
pipeTo(
dest: WritableStream<R>,
{ preventClose, preventAbort, preventCancel, signal }: PipeOptions = {},
): Promise<void> {
if (!isReadableStream(this)) {
return Promise.reject(new TypeError("Invalid ReadableStream."));
}
if (!isWritableStream(dest)) {
return Promise.reject(
new TypeError("dest is not a valid WritableStream."),
);
}
preventClose = Boolean(preventClose);
preventAbort = Boolean(preventAbort);
preventCancel = Boolean(preventCancel);
if (signal && !(signal instanceof AbortSignalImpl)) {
return Promise.reject(new TypeError("Invalid signal."));
}
if (isReadableStreamLocked(this)) {
return Promise.reject(new TypeError("ReadableStream is locked."));
}
if (isWritableStreamLocked(dest)) {
return Promise.reject(new TypeError("dest is locked."));
}
return readableStreamPipeTo(
this,
dest,
preventClose,
preventAbort,
preventCancel,
signal,
);
}
tee(): [ReadableStreamImpl<R>, ReadableStreamImpl<R>] {
if (!isReadableStream(this)) {
throw new TypeError("Invalid ReadableStream.");
}
return readableStreamTee(this, false);
}
[customInspect](): string {
return `${this.constructor.name} { locked: ${String(this.locked)} }`;
}
[Symbol.asyncIterator](
options: {
preventCancel?: boolean;
} = {},
): AsyncIterableIterator<R> {
return this.getIterator(options);
}
}
setFunctionName(ReadableStreamImpl, "ReadableStream");