summaryrefslogtreecommitdiff
path: root/cli/rt
diff options
context:
space:
mode:
Diffstat (limited to 'cli/rt')
-rw-r--r--cli/rt/01_web_util.js32
-rw-r--r--cli/rt/02_console.js5
-rw-r--r--cli/rt/03_dom_iterable.js77
-rw-r--r--cli/rt/11_streams.js3280
-rw-r--r--cli/rt/20_blob.js223
-rw-r--r--cli/rt/20_headers.js256
-rw-r--r--cli/rt/20_streams_queuing_strategy.js50
-rw-r--r--cli/rt/21_dom_file.js27
-rw-r--r--cli/rt/22_form_data.js116
-rw-r--r--cli/rt/23_multipart.js199
-rw-r--r--cli/rt/24_body.js220
-rw-r--r--cli/rt/25_request.js139
-rw-r--r--cli/rt/26_fetch.js391
-rw-r--r--cli/rt/28_filereader.js (renamed from cli/rt/21_filereader.js)0
-rw-r--r--cli/rt/99_main.js17
15 files changed, 10 insertions, 5022 deletions
diff --git a/cli/rt/01_web_util.js b/cli/rt/01_web_util.js
index d64ef28c3..1b7f7b83a 100644
--- a/cli/rt/01_web_util.js
+++ b/cli/rt/01_web_util.js
@@ -1,10 +1,6 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
((window) => {
- function isTypedArray(x) {
- return ArrayBuffer.isView(x) && !(x instanceof DataView);
- }
-
function isInvalidDate(x) {
return isNaN(x.getTime());
}
@@ -149,40 +145,12 @@
}
}
- function getHeaderValueParams(value) {
- const params = new Map();
- // Forced to do so for some Map constructor param mismatch
- value
- .split(";")
- .slice(1)
- .map((s) => s.trim().split("="))
- .filter((arr) => arr.length > 1)
- .map(([k, v]) => [k, v.replace(/^"([^"]*)"$/, "$1")])
- .forEach(([k, v]) => params.set(k, v));
- return params;
- }
-
- function hasHeaderValueOf(s, value) {
- return new RegExp(`^${value}[\t\s]*;?`).test(s);
- }
-
- /** An internal function which provides a function name for some generated
- * functions, so stack traces are a bit more readable.
- */
- function setFunctionName(fn, value) {
- Object.defineProperty(fn, "name", { value, configurable: true });
- }
-
window.__bootstrap.webUtil = {
- isTypedArray,
isInvalidDate,
requiredArguments,
immutableDefine,
hasOwnProperty,
cloneValue,
defineEnumerableProps,
- getHeaderValueParams,
- hasHeaderValueOf,
- setFunctionName,
};
})(this);
diff --git a/cli/rt/02_console.js b/cli/rt/02_console.js
index a5e6595b9..34e106ff2 100644
--- a/cli/rt/02_console.js
+++ b/cli/rt/02_console.js
@@ -15,7 +15,6 @@
} = window.__bootstrap.colors;
const {
- isTypedArray,
isInvalidDate,
hasOwnProperty,
} = window.__bootstrap.webUtil;
@@ -23,6 +22,10 @@
// Copyright Joyent, Inc. and other Node contributors. MIT license.
// Forked from Node's lib/internal/cli_table.js
+ function isTypedArray(x) {
+ return ArrayBuffer.isView(x) && !(x instanceof DataView);
+ }
+
const tableChars = {
middleMiddle: "─",
rowMiddle: "┼",
diff --git a/cli/rt/03_dom_iterable.js b/cli/rt/03_dom_iterable.js
deleted file mode 100644
index cd190b9cd..000000000
--- a/cli/rt/03_dom_iterable.js
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-((window) => {
- const { requiredArguments } = window.__bootstrap.webUtil;
- const { exposeForTest } = window.__bootstrap.internals;
-
- function DomIterableMixin(
- Base,
- dataSymbol,
- ) {
- // we have to cast `this` as `any` because there is no way to describe the
- // Base class in a way where the Symbol `dataSymbol` is defined. So the
- // runtime code works, but we do lose a little bit of type safety.
-
- // Additionally, we have to not use .keys() nor .values() since the internal
- // slot differs in type - some have a Map, which yields [K, V] in
- // Symbol.iterator, and some have an Array, which yields V, in this case
- // [K, V] too as they are arrays of tuples.
-
- const DomIterable = class extends Base {
- *entries() {
- for (const entry of this[dataSymbol]) {
- yield entry;
- }
- }
-
- *keys() {
- for (const [key] of this[dataSymbol]) {
- yield key;
- }
- }
-
- *values() {
- for (const [, value] of this[dataSymbol]) {
- yield value;
- }
- }
-
- forEach(
- callbackfn,
- thisArg,
- ) {
- requiredArguments(
- `${this.constructor.name}.forEach`,
- arguments.length,
- 1,
- );
- callbackfn = callbackfn.bind(
- thisArg == null ? globalThis : Object(thisArg),
- );
- for (const [key, value] of this[dataSymbol]) {
- callbackfn(value, key, this);
- }
- }
-
- *[Symbol.iterator]() {
- for (const entry of this[dataSymbol]) {
- yield entry;
- }
- }
- };
-
- // we want the Base class name to be the name of the class.
- Object.defineProperty(DomIterable, "name", {
- value: Base.name,
- configurable: true,
- });
-
- return DomIterable;
- }
-
- exposeForTest("DomIterableMixin", DomIterableMixin);
-
- window.__bootstrap.domIterable = {
- DomIterableMixin,
- };
-})(this);
diff --git a/cli/rt/11_streams.js b/cli/rt/11_streams.js
deleted file mode 100644
index 630878e74..000000000
--- a/cli/rt/11_streams.js
+++ /dev/null
@@ -1,3280 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-// This code closely follows the WHATWG Stream Specification
-// See: https://streams.spec.whatwg.org/
-//
-// There are some parts that are not fully implemented, and there are some
-// comments which point to steps of the specification that are not implemented.
-
-((window) => {
- /* eslint-disable @typescript-eslint/no-explicit-any,require-await */
-
- const { cloneValue, setFunctionName } = window.__bootstrap.webUtil;
- const { assert, AssertionError } = window.__bootstrap.util;
-
- const customInspect = Symbol.for("Deno.customInspect");
-
- const sym = {
- abortAlgorithm: Symbol("abortAlgorithm"),
- abortSteps: Symbol("abortSteps"),
- asyncIteratorReader: Symbol("asyncIteratorReader"),
- autoAllocateChunkSize: Symbol("autoAllocateChunkSize"),
- backpressure: Symbol("backpressure"),
- backpressureChangePromise: Symbol("backpressureChangePromise"),
- byobRequest: Symbol("byobRequest"),
- cancelAlgorithm: Symbol("cancelAlgorithm"),
- cancelSteps: Symbol("cancelSteps"),
- closeAlgorithm: Symbol("closeAlgorithm"),
- closedPromise: Symbol("closedPromise"),
- closeRequest: Symbol("closeRequest"),
- closeRequested: Symbol("closeRequested"),
- controlledReadableByteStream: Symbol(
- "controlledReadableByteStream",
- ),
- controlledReadableStream: Symbol("controlledReadableStream"),
- controlledTransformStream: Symbol("controlledTransformStream"),
- controlledWritableStream: Symbol("controlledWritableStream"),
- disturbed: Symbol("disturbed"),
- errorSteps: Symbol("errorSteps"),
- flushAlgorithm: Symbol("flushAlgorithm"),
- forAuthorCode: Symbol("forAuthorCode"),
- inFlightWriteRequest: Symbol("inFlightWriteRequest"),
- inFlightCloseRequest: Symbol("inFlightCloseRequest"),
- isFakeDetached: Symbol("isFakeDetached"),
- ownerReadableStream: Symbol("ownerReadableStream"),
- ownerWritableStream: Symbol("ownerWritableStream"),
- pendingAbortRequest: Symbol("pendingAbortRequest"),
- preventCancel: Symbol("preventCancel"),
- pullAgain: Symbol("pullAgain"),
- pullAlgorithm: Symbol("pullAlgorithm"),
- pulling: Symbol("pulling"),
- pullSteps: Symbol("pullSteps"),
- queue: Symbol("queue"),
- queueTotalSize: Symbol("queueTotalSize"),
- readable: Symbol("readable"),
- readableStreamController: Symbol("readableStreamController"),
- reader: Symbol("reader"),
- readRequests: Symbol("readRequests"),
- readyPromise: Symbol("readyPromise"),
- started: Symbol("started"),
- state: Symbol("state"),
- storedError: Symbol("storedError"),
- strategyHWM: Symbol("strategyHWM"),
- strategySizeAlgorithm: Symbol("strategySizeAlgorithm"),
- transformAlgorithm: Symbol("transformAlgorithm"),
- transformStreamController: Symbol("transformStreamController"),
- writableStreamController: Symbol("writableStreamController"),
- writeAlgorithm: Symbol("writeAlgorithm"),
- writable: Symbol("writable"),
- writer: Symbol("writer"),
- writeRequests: Symbol("writeRequests"),
- };
- class ReadableByteStreamController {
- constructor() {
- throw new TypeError(
- "ReadableByteStreamController's constructor cannot be called.",
- );
- }
-
- get byobRequest() {
- return undefined;
- }
-
- get desiredSize() {
- if (!isReadableByteStreamController(this)) {
- throw new TypeError("Invalid ReadableByteStreamController.");
- }
- return readableByteStreamControllerGetDesiredSize(this);
- }
-
- close() {
- if (!isReadableByteStreamController(this)) {
- throw new TypeError("Invalid ReadableByteStreamController.");
- }
- if (this[sym.closeRequested]) {
- throw new TypeError("Closed already requested.");
- }
- if (this[sym.controlledReadableByteStream][sym.state] !== "readable") {
- throw new TypeError(
- "ReadableByteStreamController's stream is not in a readable state.",
- );
- }
- readableByteStreamControllerClose(this);
- }
-
- enqueue(chunk) {
- if (!isReadableByteStreamController(this)) {
- throw new TypeError("Invalid ReadableByteStreamController.");
- }
- if (this[sym.closeRequested]) {
- throw new TypeError("Closed already requested.");
- }
- if (this[sym.controlledReadableByteStream][sym.state] !== "readable") {
- throw new TypeError(
- "ReadableByteStreamController's stream is not in a readable state.",
- );
- }
- if (!ArrayBuffer.isView(chunk)) {
- throw new TypeError(
- "You can only enqueue array buffer views when using a ReadableByteStreamController",
- );
- }
- if (isDetachedBuffer(chunk.buffer)) {
- throw new TypeError(
- "Cannot enqueue a view onto a detached ArrayBuffer",
- );
- }
- readableByteStreamControllerEnqueue(this, chunk);
- }
-
- error(error) {
- if (!isReadableByteStreamController(this)) {
- throw new TypeError("Invalid ReadableByteStreamController.");
- }
- readableByteStreamControllerError(this, error);
- }
-
- [sym.cancelSteps](reason) {
- // 3.11.5.1.1 If this.[[pendingPullIntos]] is not empty,
- resetQueue(this);
- const result = this[sym.cancelAlgorithm](reason);
- readableByteStreamControllerClearAlgorithms(this);
- return result;
- }
-
- [sym.pullSteps]() {
- const stream = this[sym.controlledReadableByteStream];
- assert(readableStreamHasDefaultReader(stream));
- if (this[sym.queueTotalSize] > 0) {
- assert(readableStreamGetNumReadRequests(stream) === 0);
- const entry = this[sym.queue].shift();
- assert(entry);
- this[sym.queueTotalSize] -= entry.size;
- readableByteStreamControllerHandleQueueDrain(this);
- const view = new Uint8Array(entry.value, entry.offset, entry.size);
- return Promise.resolve(
- readableStreamCreateReadResult(
- view,
- false,
- stream[sym.reader][sym.forAuthorCode],
- ),
- );
- }
- // 3.11.5.2.5 If autoAllocateChunkSize is not undefined,
- const promise = readableStreamAddReadRequest(stream);
- readableByteStreamControllerCallPullIfNeeded(this);
- return promise;
- }
-
- [customInspect]() {
- return `${this.constructor.name} { byobRequest: ${
- String(this.byobRequest)
- }, desiredSize: ${String(this.desiredSize)} }`;
- }
- }
-
- class ReadableStreamDefaultController {
- constructor() {
- throw new TypeError(
- "ReadableStreamDefaultController's constructor cannot be called.",
- );
- }
-
- get desiredSize() {
- if (!isReadableStreamDefaultController(this)) {
- throw new TypeError("Invalid ReadableStreamDefaultController.");
- }
- return readableStreamDefaultControllerGetDesiredSize(this);
- }
-
- close() {
- if (!isReadableStreamDefaultController(this)) {
- throw new TypeError("Invalid ReadableStreamDefaultController.");
- }
- if (!readableStreamDefaultControllerCanCloseOrEnqueue(this)) {
- throw new TypeError(
- "ReadableStreamDefaultController cannot close or enqueue.",
- );
- }
- readableStreamDefaultControllerClose(this);
- }
-
- enqueue(chunk) {
- if (!isReadableStreamDefaultController(this)) {
- throw new TypeError("Invalid ReadableStreamDefaultController.");
- }
- if (!readableStreamDefaultControllerCanCloseOrEnqueue(this)) {
- throw new TypeError("ReadableSteamController cannot enqueue.");
- }
- return readableStreamDefaultControllerEnqueue(this, chunk);
- }
-
- error(error) {
- if (!isReadableStreamDefaultController(this)) {
- throw new TypeError("Invalid ReadableStreamDefaultController.");
- }
- readableStreamDefaultControllerError(this, error);
- }
-
- [sym.cancelSteps](reason) {
- resetQueue(this);
- const result = this[sym.cancelAlgorithm](reason);
- readableStreamDefaultControllerClearAlgorithms(this);
- return result;
- }
-
- [sym.pullSteps]() {
- const stream = this[sym.controlledReadableStream];
- if (this[sym.queue].length) {
- const chunk = dequeueValue(this);
- if (this[sym.closeRequested] && this[sym.queue].length === 0) {
- readableStreamDefaultControllerClearAlgorithms(this);
- readableStreamClose(stream);
- } else {
- readableStreamDefaultControllerCallPullIfNeeded(this);
- }
- return Promise.resolve(
- readableStreamCreateReadResult(
- chunk,
- false,
- stream[sym.reader][sym.forAuthorCode],
- ),
- );
- }
- const pendingPromise = readableStreamAddReadRequest(stream);
- readableStreamDefaultControllerCallPullIfNeeded(this);
- return pendingPromise;
- }
-
- [customInspect]() {
- return `${this.constructor.name} { desiredSize: ${
- String(this.desiredSize)
- } }`;
- }
- }
-
- class ReadableStreamDefaultReader {
- constructor(stream) {
- if (!isReadableStream(stream)) {
- throw new TypeError("stream is not a ReadableStream.");
- }
- if (isReadableStreamLocked(stream)) {
- throw new TypeError("stream is locked.");
- }
- readableStreamReaderGenericInitialize(this, stream);
- this[sym.readRequests] = [];
- }
-
- get closed() {
- if (!isReadableStreamDefaultReader(this)) {
- return Promise.reject(
- new TypeError("Invalid ReadableStreamDefaultReader."),
- );
- }
- return (
- this[sym.closedPromise].promise ??
- Promise.reject(new TypeError("Invalid reader."))
- );
- }
-
- cancel(reason) {
- if (!isReadableStreamDefaultReader(this)) {
- return Promise.reject(
- new TypeError("Invalid ReadableStreamDefaultReader."),
- );
- }
- if (!this[sym.ownerReadableStream]) {
- return Promise.reject(new TypeError("Invalid reader."));
- }
- return readableStreamReaderGenericCancel(this, reason);
- }
-
- read() {
- if (!isReadableStreamDefaultReader(this)) {
- return Promise.reject(
- new TypeError("Invalid ReadableStreamDefaultReader."),
- );
- }
- if (!this[sym.ownerReadableStream]) {
- return Promise.reject(new TypeError("Invalid reader."));
- }
- return readableStreamDefaultReaderRead(this);
- }
-
- releaseLock() {
- if (!isReadableStreamDefaultReader(this)) {
- throw new TypeError("Invalid ReadableStreamDefaultReader.");
- }
- if (this[sym.ownerReadableStream] === undefined) {
- return;
- }
- if (this[sym.readRequests].length) {
- throw new TypeError("Cannot release lock with pending read requests.");
- }
- readableStreamReaderGenericRelease(this);
- }
-
- [customInspect]() {
- return `${this.constructor.name} { closed: Promise }`;
- }
- }
-
- const AsyncIteratorPrototype = Object
- .getPrototypeOf(Object.getPrototypeOf(async function* () {}).prototype);
-
- const ReadableStreamAsyncIteratorPrototype = Object.setPrototypeOf({
- next() {
- if (!isReadableStreamAsyncIterator(this)) {
- return Promise.reject(
- new TypeError("invalid ReadableStreamAsyncIterator."),
- );
- }
- const reader = this[sym.asyncIteratorReader];
- if (!reader[sym.ownerReadableStream]) {
- return Promise.reject(
- new TypeError("reader owner ReadableStream is undefined."),
- );
- }
- return readableStreamDefaultReaderRead(reader).then((result) => {
- assert(typeof result === "object");
- const { done } = result;
- assert(typeof done === "boolean");
- if (done) {
- readableStreamReaderGenericRelease(reader);
- }
- const { value } = result;
- return readableStreamCreateReadResult(value, done, true);
- });
- },
- return(
- value,
- ) {
- if (!isReadableStreamAsyncIterator(this)) {
- return Promise.reject(
- new TypeError("invalid ReadableStreamAsyncIterator."),
- );
- }
- const reader = this[sym.asyncIteratorReader];
- if (!reader[sym.ownerReadableStream]) {
- return Promise.reject(
- new TypeError("reader owner ReadableStream is undefined."),
- );
- }
- if (reader[sym.readRequests].length) {
- return Promise.reject(
- new TypeError("reader has outstanding read requests."),
- );
- }
- if (!this[sym.preventCancel]) {
- const result = readableStreamReaderGenericCancel(reader, value);
- readableStreamReaderGenericRelease(reader);
- return result.then(() =>
- readableStreamCreateReadResult(value, true, true)
- );
- }
- readableStreamReaderGenericRelease(reader);
- return Promise.resolve(
- readableStreamCreateReadResult(value, true, true),
- );
- },
- }, AsyncIteratorPrototype);
-
- class ReadableStream {
- constructor(
- underlyingSource = {},
- strategy = {},
- ) {
- initializeReadableStream(this);
- const { size } = strategy;
- let { highWaterMark } = strategy;
- const { type } = underlyingSource;
-
- if (underlyingSource.type == "bytes") {
- 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() {
- if (!isReadableStream(this)) {
- throw new TypeError("Invalid ReadableStream.");
- }
- return isReadableStreamLocked(this);
- }
-
- cancel(reason) {
- 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,
- } = {}) {
- 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 } = {}) {
- 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(
- {
- writable,
- readable,
- },
- { preventClose, preventAbort, preventCancel, signal } = {},
- ) {
- 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 AbortSignal)) {
- 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,
- { preventClose, preventAbort, preventCancel, signal } = {},
- ) {
- 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 AbortSignal)) {
- 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() {
- if (!isReadableStream(this)) {
- throw new TypeError("Invalid ReadableStream.");
- }
- return readableStreamTee(this, false);
- }
-
- [customInspect]() {
- return `${this.constructor.name} { locked: ${String(this.locked)} }`;
- }
-
- [Symbol.asyncIterator](
- options = {},
- ) {
- return this.getIterator(options);
- }
- }
-
- class TransformStream {
- constructor(
- transformer = {},
- writableStrategy = {},
- readableStrategy = {},
- ) {
- const writableSizeFunction = writableStrategy.size;
- let writableHighWaterMark = writableStrategy.highWaterMark;
- const readableSizeFunction = readableStrategy.size;
- let readableHighWaterMark = readableStrategy.highWaterMark;
- const writableType = transformer.writableType;
- if (writableType !== undefined) {
- throw new RangeError(
- `Expected transformer writableType to be undefined, received "${
- String(writableType)
- }"`,
- );
- }
- const writableSizeAlgorithm = makeSizeAlgorithmFromSizeFunction(
- writableSizeFunction,
- );
- if (writableHighWaterMark === undefined) {
- writableHighWaterMark = 1;
- }
- writableHighWaterMark = validateAndNormalizeHighWaterMark(
- writableHighWaterMark,
- );
- const readableType = transformer.readableType;
- if (readableType !== undefined) {
- throw new RangeError(
- `Expected transformer readableType to be undefined, received "${
- String(readableType)
- }"`,
- );
- }
- const readableSizeAlgorithm = makeSizeAlgorithmFromSizeFunction(
- readableSizeFunction,
- );
- if (readableHighWaterMark === undefined) {
- readableHighWaterMark = 1;
- }
- readableHighWaterMark = validateAndNormalizeHighWaterMark(
- readableHighWaterMark,
- );
- const startPromise = getDeferred();
- initializeTransformStream(
- this,
- startPromise.promise,
- writableHighWaterMark,
- writableSizeAlgorithm,
- readableHighWaterMark,
- readableSizeAlgorithm,
- );
- // the brand check expects this, and the brand check occurs in the following
- // but the property hasn't been defined.
- Object.defineProperty(this, sym.transformStreamController, {
- value: undefined,
- writable: true,
- configurable: true,
- });
- setUpTransformStreamDefaultControllerFromTransformer(this, transformer);
- const startResult = invokeOrNoop(
- transformer,
- "start",
- this[sym.transformStreamController],
- );
- startPromise.resolve(startResult);
- }
-
- get readable() {
- if (!isTransformStream(this)) {
- throw new TypeError("Invalid TransformStream.");
- }
- return this[sym.readable];
- }
-
- get writable() {
- if (!isTransformStream(this)) {
- throw new TypeError("Invalid TransformStream.");
- }
- return this[sym.writable];
- }
-
- [customInspect]() {
- return this.constructor.name;
- }
- }
-
- class TransformStreamDefaultController {
- constructor() {
- throw new TypeError(
- "TransformStreamDefaultController's constructor cannot be called.",
- );
- }
-
- get desiredSize() {
- if (!isTransformStreamDefaultController(this)) {
- throw new TypeError("Invalid TransformStreamDefaultController.");
- }
- const readableController = this[sym.controlledTransformStream][
- sym.readable
- ][sym.readableStreamController];
- return readableStreamDefaultControllerGetDesiredSize(
- readableController,
- );
- }
-
- enqueue(chunk) {
- if (!isTransformStreamDefaultController(this)) {
- throw new TypeError("Invalid TransformStreamDefaultController.");
- }
- transformStreamDefaultControllerEnqueue(this, chunk);
- }
-
- error(reason) {
- if (!isTransformStreamDefaultController(this)) {
- throw new TypeError("Invalid TransformStreamDefaultController.");
- }
- transformStreamDefaultControllerError(this, reason);
- }
-
- terminate() {
- if (!isTransformStreamDefaultController(this)) {
- throw new TypeError("Invalid TransformStreamDefaultController.");
- }
- transformStreamDefaultControllerTerminate(this);
- }
-
- [customInspect]() {
- return `${this.constructor.name} { desiredSize: ${
- String(this.desiredSize)
- } }`;
- }
- }
-
- class WritableStreamDefaultController {
- constructor() {
- throw new TypeError(
- "WritableStreamDefaultController's constructor cannot be called.",
- );
- }
-
- error(e) {
- if (!isWritableStreamDefaultController(this)) {
- throw new TypeError("Invalid WritableStreamDefaultController.");
- }
- const state = this[sym.controlledWritableStream][sym.state];
- if (state !== "writable") {
- return;
- }
- writableStreamDefaultControllerError(this, e);
- }
-
- [sym.abortSteps](reason) {
- const result = this[sym.abortAlgorithm](reason);
- writableStreamDefaultControllerClearAlgorithms(this);
- return result;
- }
-
- [sym.errorSteps]() {
- resetQueue(this);
- }
-
- [customInspect]() {
- return `${this.constructor.name} { }`;
- }
- }
-
- class WritableStreamDefaultWriter {
- constructor(stream) {
- if (!isWritableStream(stream)) {
- throw new TypeError("Invalid stream.");
- }
- if (isWritableStreamLocked(stream)) {
- throw new TypeError("Cannot create a writer for a locked stream.");
- }
- this[sym.ownerWritableStream] = stream;
- stream[sym.writer] = this;
- const state = stream[sym.state];
- if (state === "writable") {
- if (
- !writableStreamCloseQueuedOrInFlight(stream) &&
- stream[sym.backpressure]
- ) {
- this[sym.readyPromise] = getDeferred();
- } else {
- this[sym.readyPromise] = { promise: Promise.resolve() };
- }
- this[sym.closedPromise] = getDeferred();
- } else if (state === "erroring") {
- this[sym.readyPromise] = {
- promise: Promise.reject(stream[sym.storedError]),
- };
- setPromiseIsHandledToTrue(this[sym.readyPromise].promise);
- this[sym.closedPromise] = getDeferred();
- } else if (state === "closed") {
- this[sym.readyPromise] = { promise: Promise.resolve() };
- this[sym.closedPromise] = { promise: Promise.resolve() };
- } else {
- assert(state === "errored");
- const storedError = stream[sym.storedError];
- this[sym.readyPromise] = { promise: Promise.reject(storedError) };
- setPromiseIsHandledToTrue(this[sym.readyPromise].promise);
- this[sym.closedPromise] = { promise: Promise.reject(storedError) };
- setPromiseIsHandledToTrue(this[sym.closedPromise].promise);
- }
- }
-
- get closed() {
- if (!isWritableStreamDefaultWriter(this)) {
- return Promise.reject(
- new TypeError("Invalid WritableStreamDefaultWriter."),
- );
- }
- return this[sym.closedPromise].promise;
- }
-
- get desiredSize() {
- if (!isWritableStreamDefaultWriter(this)) {
- throw new TypeError("Invalid WritableStreamDefaultWriter.");
- }
- if (!this[sym.ownerWritableStream]) {
- throw new TypeError("WritableStreamDefaultWriter has no owner.");
- }
- return writableStreamDefaultWriterGetDesiredSize(this);
- }
-
- get ready() {
- if (!isWritableStreamDefaultWriter(this)) {
- return Promise.reject(
- new TypeError("Invalid WritableStreamDefaultWriter."),
- );
- }
- return this[sym.readyPromise].promise;
- }
-
- abort(reason) {
- if (!isWritableStreamDefaultWriter(this)) {
- return Promise.reject(
- new TypeError("Invalid WritableStreamDefaultWriter."),
- );
- }
- if (!this[sym.ownerWritableStream]) {
- Promise.reject(
- new TypeError("WritableStreamDefaultWriter has no owner."),
- );
- }
- return writableStreamDefaultWriterAbort(this, reason);
- }
-
- close() {
- if (!isWritableStreamDefaultWriter(this)) {
- return Promise.reject(
- new TypeError("Invalid WritableStreamDefaultWriter."),
- );
- }
- const stream = this[sym.ownerWritableStream];
- if (!stream) {
- Promise.reject(
- new TypeError("WritableStreamDefaultWriter has no owner."),
- );
- }
- if (writableStreamCloseQueuedOrInFlight(stream)) {
- Promise.reject(
- new TypeError("Stream is in an invalid state to be closed."),
- );
- }
- return writableStreamDefaultWriterClose(this);
- }
-
- releaseLock() {
- if (!isWritableStreamDefaultWriter(this)) {
- throw new TypeError("Invalid WritableStreamDefaultWriter.");
- }
- const stream = this[sym.ownerWritableStream];
- if (!stream) {
- return;
- }
- assert(stream[sym.writer]);
- writableStreamDefaultWriterRelease(this);
- }
-
- write(chunk) {
- if (!isWritableStreamDefaultWriter(this)) {
- return Promise.reject(
- new TypeError("Invalid WritableStreamDefaultWriter."),
- );
- }
- if (!this[sym.ownerWritableStream]) {
- Promise.reject(
- new TypeError("WritableStreamDefaultWriter has no owner."),
- );
- }
- return writableStreamDefaultWriterWrite(this, chunk);
- }
-
- [customInspect]() {
- return `${this.constructor.name} { closed: Promise, desiredSize: ${
- String(this.desiredSize)
- }, ready: Promise }`;
- }
- }
-
- class WritableStream {
- constructor(
- underlyingSink = {},
- strategy = {},
- ) {
- initializeWritableStream(this);
- const size = strategy.size;
- let highWaterMark = strategy.highWaterMark ?? 1;
- const { type } = underlyingSink;
- if (type !== undefined) {
- throw new RangeError(`Sink type of "${String(type)}" not supported.`);
- }
- const sizeAlgorithm = makeSizeAlgorithmFromSizeFunction(size);
- highWaterMark = validateAndNormalizeHighWaterMark(highWaterMark);
- setUpWritableStreamDefaultControllerFromUnderlyingSink(
- this,
- underlyingSink,
- highWaterMark,
- sizeAlgorithm,
- );
- }
-
- get locked() {
- if (!isWritableStream(this)) {
- throw new TypeError("Invalid WritableStream.");
- }
- return isWritableStreamLocked(this);
- }
-
- abort(reason) {
- if (!isWritableStream(this)) {
- return Promise.reject(new TypeError("Invalid WritableStream."));
- }
- if (isWritableStreamLocked(this)) {
- return Promise.reject(
- new TypeError("Cannot abort a locked WritableStream."),
- );
- }
- return writableStreamAbort(this, reason);
- }
-
- close() {
- if (!isWritableStream(this)) {
- return Promise.reject(new TypeError("Invalid WritableStream."));
- }
- if (isWritableStreamLocked(this)) {
- return Promise.reject(
- new TypeError("Cannot abort a locked WritableStream."),
- );
- }
- if (writableStreamCloseQueuedOrInFlight(this)) {
- return Promise.reject(
- new TypeError("Cannot close an already closing WritableStream."),
- );
- }
- return writableStreamClose(this);
- }
-
- getWriter() {
- if (!isWritableStream(this)) {
- throw new TypeError("Invalid WritableStream.");
- }
- return acquireWritableStreamDefaultWriter(this);
- }
-
- [customInspect]() {
- return `${this.constructor.name} { locked: ${String(this.locked)} }`;
- }
- }
-
- function acquireReadableStreamDefaultReader(
- stream,
- forAuthorCode = false,
- ) {
- const reader = new ReadableStreamDefaultReader(stream);
- reader[sym.forAuthorCode] = forAuthorCode;
- return reader;
- }
-
- function acquireWritableStreamDefaultWriter(
- stream,
- ) {
- return new WritableStreamDefaultWriter(stream);
- }
-
- function call(
- fn,
- v,
- args,
- ) {
- return Function.prototype.apply.call(fn, v, args);
- }
-
- function createAlgorithmFromUnderlyingMethod(
- underlyingObject,
- methodName,
- algoArgCount,
- ...extraArgs
- ) {
- const method = underlyingObject[methodName];
- if (method) {
- if (!isCallable(method)) {
- throw new TypeError("method is not callable");
- }
- if (algoArgCount === 0) {
- return async () => call(method, underlyingObject, extraArgs);
- } else {
- return async (arg) => {
- const fullArgs = [arg, ...extraArgs];
- return call(method, underlyingObject, fullArgs);
- };
- }
- }
- return async () => undefined;
- }
-
- function createReadableStream(
- startAlgorithm,
- pullAlgorithm,
- cancelAlgorithm,
- highWaterMark = 1,
- sizeAlgorithm = () => 1,
- ) {
- highWaterMark = validateAndNormalizeHighWaterMark(highWaterMark);
- const stream = Object.create(
- ReadableStream.prototype,
- );
- initializeReadableStream(stream);
- const controller = Object.create(
- ReadableStreamDefaultController.prototype,
- );
- setUpReadableStreamDefaultController(
- stream,
- controller,
- startAlgorithm,
- pullAlgorithm,
- cancelAlgorithm,
- highWaterMark,
- sizeAlgorithm,
- );
- return stream;
- }
-
- function createWritableStream(
- startAlgorithm,
- writeAlgorithm,
- closeAlgorithm,
- abortAlgorithm,
- highWaterMark = 1,
- sizeAlgorithm = () => 1,
- ) {
- highWaterMark = validateAndNormalizeHighWaterMark(highWaterMark);
- const stream = Object.create(WritableStream.prototype);
- initializeWritableStream(stream);
- const controller = Object.create(
- WritableStreamDefaultController.prototype,
- );
- setUpWritableStreamDefaultController(
- stream,
- controller,
- startAlgorithm,
- writeAlgorithm,
- closeAlgorithm,
- abortAlgorithm,
- highWaterMark,
- sizeAlgorithm,
- );
- return stream;
- }
-
- function dequeueValue(container) {
- assert(sym.queue in container && sym.queueTotalSize in container);
- assert(container[sym.queue].length);
- const pair = container[sym.queue].shift();
- container[sym.queueTotalSize] -= pair.size;
- if (container[sym.queueTotalSize] <= 0) {
- container[sym.queueTotalSize] = 0;
- }
- return pair.value;
- }
-
- function enqueueValueWithSize(
- container,
- value,
- size,
- ) {
- assert(sym.queue in container && sym.queueTotalSize in container);
- size = Number(size);
- if (!isFiniteNonNegativeNumber(size)) {
- throw new RangeError("size must be a finite non-negative number.");
- }
- container[sym.queue].push({ value, size });
- container[sym.queueTotalSize] += size;
- }
-
- /** Non-spec mechanism to "unwrap" a promise and store it to be resolved
- * later. */
- function getDeferred() {
- let resolve;
- let reject;
- const promise = new Promise((res, rej) => {
- resolve = res;
- reject = rej;
- });
- return { promise, resolve: resolve, reject: reject };
- }
-
- function initializeReadableStream(
- stream,
- ) {
- stream[sym.state] = "readable";
- stream[sym.reader] = stream[sym.storedError] = undefined;
- stream[sym.disturbed] = false;
- }
-
- function initializeTransformStream(
- stream,
- startPromise,
- writableHighWaterMark,
- writableSizeAlgorithm,
- readableHighWaterMark,
- readableSizeAlgorithm,
- ) {
- const startAlgorithm = () => startPromise;
- const writeAlgorithm = (chunk) =>
- transformStreamDefaultSinkWriteAlgorithm(stream, chunk);
- const abortAlgorithm = (reason) =>
- transformStreamDefaultSinkAbortAlgorithm(stream, reason);
- const closeAlgorithm = () =>
- transformStreamDefaultSinkCloseAlgorithm(stream);
- stream[sym.writable] = createWritableStream(
- startAlgorithm,
- writeAlgorithm,
- closeAlgorithm,
- abortAlgorithm,
- writableHighWaterMark,
- writableSizeAlgorithm,
- );
- const pullAlgorithm = () =>
- transformStreamDefaultSourcePullAlgorithm(stream);
- const cancelAlgorithm = (reason) => {
- transformStreamErrorWritableAndUnblockWrite(stream, reason);
- return Promise.resolve(undefined);
- };
- stream[sym.readable] = createReadableStream(
- startAlgorithm,
- pullAlgorithm,
- cancelAlgorithm,
- readableHighWaterMark,
- readableSizeAlgorithm,
- );
- stream[sym.backpressure] = stream[sym.backpressureChangePromise] =
- undefined;
- transformStreamSetBackpressure(stream, true);
- Object.defineProperty(stream, sym.transformStreamController, {
- value: undefined,
- configurable: true,
- });
- }
-
- function initializeWritableStream(
- stream,
- ) {
- stream[sym.state] = "writable";
- stream[sym.storedError] = stream[sym.writer] = stream[
- sym.writableStreamController
- ] = stream[sym.inFlightWriteRequest] = stream[sym.closeRequest] = stream[
- sym.inFlightCloseRequest
- ] = stream[sym.pendingAbortRequest] = undefined;
- stream[sym.writeRequests] = [];
- stream[sym.backpressure] = false;
- }
-
- function invokeOrNoop(
- o,
- p,
- ...args
- ) {
- assert(o);
- const method = o[p];
- if (!method) {
- return undefined;
- }
- return call(method, o, args);
- }
-
- function isCallable(value) {
- return typeof value === "function";
- }
-
- function isDetachedBuffer(value) {
- return sym.isFakeDetached in value;
- }
-
- function isFiniteNonNegativeNumber(v) {
- return Number.isFinite(v) && (v) >= 0;
- }
-
- function isReadableByteStreamController(
- x,
- ) {
- return !(
- typeof x !== "object" ||
- x === null ||
- !(sym.controlledReadableByteStream in x)
- );
- }
-
- function isReadableStream(x) {
- return !(
- typeof x !== "object" ||
- x === null ||
- !(sym.readableStreamController in x)
- );
- }
-
- function isReadableStreamAsyncIterator(
- x,
- ) {
- if (typeof x !== "object" || x === null) {
- return false;
- }
- return sym.asyncIteratorReader in x;
- }
-
- function isReadableStreamDefaultController(
- x,
- ) {
- return !(
- typeof x !== "object" ||
- x === null ||
- !(sym.controlledReadableStream in x)
- );
- }
-
- function isReadableStreamDefaultReader(
- x,
- ) {
- return !(typeof x !== "object" || x === null || !(sym.readRequests in x));
- }
-
- function isReadableStreamLocked(stream) {
- assert(isReadableStream(stream));
- return !!stream[sym.reader];
- }
-
- function isReadableStreamDisturbed(stream) {
- assert(isReadableStream(stream));
- return !!stream[sym.disturbed];
- }
-
- function isTransformStream(x) {
- return !(
- typeof x !== "object" ||
- x === null ||
- !(sym.transformStreamController in x)
- );
- }
-
- function isTransformStreamDefaultController(
- x,
- ) {
- return !(
- typeof x !== "object" ||
- x === null ||
- !(sym.controlledTransformStream in x)
- );
- }
-
- function isWritableStream(x) {
- return !(
- typeof x !== "object" ||
- x === null ||
- !(sym.writableStreamController in x)
- );
- }
-
- function isWritableStreamDefaultController(
- x,
- ) {
- return !(
- typeof x !== "object" ||
- x === null ||
- !(sym.controlledWritableStream in x)
- );
- }
-
- function isWritableStreamDefaultWriter(
- x,
- ) {
- return !(
- typeof x !== "object" ||
- x === null ||
- !(sym.ownerWritableStream in x)
- );
- }
-
- function isWritableStreamLocked(stream) {
- assert(isWritableStream(stream));
- return stream[sym.writer] !== undefined;
- }
-
- function makeSizeAlgorithmFromSizeFunction(
- size,
- ) {
- if (size === undefined) {
- return () => 1;
- }
- if (typeof size !== "function") {
- throw new TypeError("size must be callable.");
- }
- return (chunk) => {
- return size.call(undefined, chunk);
- };
- }
-
- function peekQueueValue(container) {
- assert(sym.queue in container && sym.queueTotalSize in container);
- assert(container[sym.queue].length);
- const [pair] = container[sym.queue];
- return pair.value;
- }
-
- function readableByteStreamControllerShouldCallPull(
- controller,
- ) {
- const stream = controller[sym.controlledReadableByteStream];
- if (
- stream[sym.state] !== "readable" ||
- controller[sym.closeRequested] ||
- !controller[sym.started]
- ) {
- return false;
- }
- if (
- readableStreamHasDefaultReader(stream) &&
- readableStreamGetNumReadRequests(stream) > 0
- ) {
- return true;
- }
- // 3.13.25.6 If ! ReadableStreamHasBYOBReader(stream) is true and !
- // ReadableStreamGetNumReadIntoRequests(stream) > 0, return true.
- const desiredSize = readableByteStreamControllerGetDesiredSize(controller);
- assert(desiredSize !== null);
- return desiredSize > 0;
- }
-
- function readableByteStreamControllerCallPullIfNeeded(
- controller,
- ) {
- const shouldPull = readableByteStreamControllerShouldCallPull(controller);
- if (!shouldPull) {
- return;
- }
- if (controller[sym.pulling]) {
- controller[sym.pullAgain] = true;
- return;
- }
- assert(controller[sym.pullAgain] === false);
- controller[sym.pulling] = true;
- const pullPromise = controller[sym.pullAlgorithm]();
- setPromiseIsHandledToTrue(
- pullPromise.then(
- () => {
- controller[sym.pulling] = false;
- if (controller[sym.pullAgain]) {
- controller[sym.pullAgain] = false;
- readableByteStreamControllerCallPullIfNeeded(controller);
- }
- },
- (e) => {
- readableByteStreamControllerError(controller, e);
- },
- ),
- );
- }
-
- function readableByteStreamControllerClearAlgorithms(
- controller,
- ) {
- controller[sym.pullAlgorithm] = undefined;
- controller[sym.cancelAlgorithm] = undefined;
- }
-
- function readableByteStreamControllerClose(
- controller,
- ) {
- const stream = controller[sym.controlledReadableByteStream];
- if (controller[sym.closeRequested] || stream[sym.state] !== "readable") {
- return;
- }
- if (controller[sym.queueTotalSize] > 0) {
- controller[sym.closeRequested] = true;
- return;
- }
- // 3.13.6.4 If controller.[[pendingPullIntos]] is not empty, (BYOB Support)
- readableByteStreamControllerClearAlgorithms(controller);
- readableStreamClose(stream);
- }
-
- function readableByteStreamControllerEnqueue(
- controller,
- chunk,
- ) {
- const stream = controller[sym.controlledReadableByteStream];
- if (controller[sym.closeRequested] || stream[sym.state] !== "readable") {
- return;
- }
- const { buffer, byteOffset, byteLength } = chunk;
- const transferredBuffer = transferArrayBuffer(buffer);
- if (readableStreamHasDefaultReader(stream)) {
- if (readableStreamGetNumReadRequests(stream) === 0) {
- readableByteStreamControllerEnqueueChunkToQueue(
- controller,
- transferredBuffer,
- byteOffset,
- byteLength,
- );
- } else {
- assert(controller[sym.queue].length === 0);
- const transferredView = new Uint8Array(
- transferredBuffer,
- byteOffset,
- byteLength,
- );
- readableStreamFulfillReadRequest(stream, transferredView, false);
- }
- // 3.13.9.8 Otherwise, if ! ReadableStreamHasBYOBReader(stream) is true
- } else {
- assert(!isReadableStreamLocked(stream));
- readableByteStreamControllerEnqueueChunkToQueue(
- controller,
- transferredBuffer,
- byteOffset,
- byteLength,
- );
- }
- readableByteStreamControllerCallPullIfNeeded(controller);
- }
-
- function readableByteStreamControllerEnqueueChunkToQueue(
- controller,
- buffer,
- byteOffset,
- byteLength,
- ) {
- controller[sym.queue].push({
- value: buffer,
- offset: byteOffset,
- size: byteLength,
- });
- controller[sym.queueTotalSize] += byteLength;
- }
-
- function readableByteStreamControllerError(
- controller,
- e,
- ) {
- const stream = controller[sym.controlledReadableByteStream];
- if (stream[sym.state] !== "readable") {
- return;
- }
- // 3.13.11.3 Perform ! ReadableByteStreamControllerClearPendingPullIntos(controller).
- resetQueue(controller);
- readableByteStreamControllerClearAlgorithms(controller);
- readableStreamError(stream, e);
- }
-
- function readableByteStreamControllerGetDesiredSize(
- controller,
- ) {
- const stream = controller[sym.controlledReadableByteStream];
- const state = stream[sym.state];
- if (state === "errored") {
- return null;
- }
- if (state === "closed") {
- return 0;
- }
- return controller[sym.strategyHWM] - controller[sym.queueTotalSize];
- }
-
- function readableByteStreamControllerHandleQueueDrain(
- controller,
- ) {
- assert(
- controller[sym.controlledReadableByteStream][sym.state] === "readable",
- );
- if (
- controller[sym.queueTotalSize] === 0 && controller[sym.closeRequested]
- ) {
- readableByteStreamControllerClearAlgorithms(controller);
- readableStreamClose(controller[sym.controlledReadableByteStream]);
- } else {
- readableByteStreamControllerCallPullIfNeeded(controller);
- }
- }
-
- function readableStreamAddReadRequest(
- stream,
- ) {
- assert(isReadableStreamDefaultReader(stream[sym.reader]));
- assert(stream[sym.state] === "readable");
- const promise = getDeferred();
- stream[sym.reader][sym.readRequests].push(promise);
- return promise.promise;
- }
-
- function readableStreamCancel(
- stream,
- reason,
- ) {
- stream[sym.disturbed] = true;
- if (stream[sym.state] === "closed") {
- return Promise.resolve();
- }
- if (stream[sym.state] === "errored") {
- return Promise.reject(stream[sym.storedError]);
- }
- readableStreamClose(stream);
- return stream[sym.readableStreamController][sym.cancelSteps](reason).then(
- () => undefined,
- );
- }
-
- function readableStreamClose(stream) {
- assert(stream[sym.state] === "readable");
- stream[sym.state] = "closed";
- const reader = stream[sym.reader];
- if (!reader) {
- return;
- }
- if (isReadableStreamDefaultReader(reader)) {
- for (const readRequest of reader[sym.readRequests]) {
- assert(readRequest.resolve);
- readRequest.resolve(
- readableStreamCreateReadResult(
- undefined,
- true,
- reader[sym.forAuthorCode],
- ),
- );
- }
- reader[sym.readRequests] = [];
- }
- const resolve = reader[sym.closedPromise].resolve;
- assert(resolve);
- resolve();
- }
-
- function readableStreamCreateReadResult(
- value,
- done,
- forAuthorCode,
- ) {
- const prototype = forAuthorCode ? Object.prototype : null;
- assert(typeof done === "boolean");
- const obj = Object.create(prototype);
- Object.defineProperties(obj, {
- value: { value, writable: true, enumerable: true, configurable: true },
- done: {
- value: done,
- writable: true,
- enumerable: true,
- configurable: true,
- },
- });
- return obj;
- }
-
- function readableStreamDefaultControllerCallPullIfNeeded(
- controller,
- ) {
- const shouldPull = readableStreamDefaultControllerShouldCallPull(
- controller,
- );
- if (!shouldPull) {
- return;
- }
- if (controller[sym.pulling]) {
- controller[sym.pullAgain] = true;
- return;
- }
- assert(controller[sym.pullAgain] === false);
- controller[sym.pulling] = true;
- const pullPromise = controller[sym.pullAlgorithm]();
- pullPromise.then(
- () => {
- controller[sym.pulling] = false;
- if (controller[sym.pullAgain]) {
- controller[sym.pullAgain] = false;
- readableStreamDefaultControllerCallPullIfNeeded(controller);
- }
- },
- (e) => {
- readableStreamDefaultControllerError(controller, e);
- },
- );
- }
-
- function readableStreamDefaultControllerCanCloseOrEnqueue(
- controller,
- ) {
- const state = controller[sym.controlledReadableStream][sym.state];
- return !controller[sym.closeRequested] && state === "readable";
- }
-
- function readableStreamDefaultControllerClearAlgorithms(
- controller,
- ) {
- controller[sym.pullAlgorithm] = undefined;
- controller[sym.cancelAlgorithm] = undefined;
- controller[sym.strategySizeAlgorithm] = undefined;
- }
-
- function readableStreamDefaultControllerClose(
- controller,
- ) {
- if (!readableStreamDefaultControllerCanCloseOrEnqueue(controller)) {
- return;
- }
- const stream = controller[sym.controlledReadableStream];
- controller[sym.closeRequested] = true;
- if (controller[sym.queue].length === 0) {
- readableStreamDefaultControllerClearAlgorithms(controller);
- readableStreamClose(stream);
- }
- }
-
- function readableStreamDefaultControllerEnqueue(
- controller,
- chunk,
- ) {
- if (!readableStreamDefaultControllerCanCloseOrEnqueue(controller)) {
- return;
- }
- const stream = controller[sym.controlledReadableStream];
- if (
- isReadableStreamLocked(stream) &&
- readableStreamGetNumReadRequests(stream) > 0
- ) {
- readableStreamFulfillReadRequest(stream, chunk, false);
- } else {
- try {
- const chunkSize = controller[sym.strategySizeAlgorithm](chunk);
- enqueueValueWithSize(controller, chunk, chunkSize);
- } catch (err) {
- readableStreamDefaultControllerError(controller, err);
- throw err;
- }
- }
- readableStreamDefaultControllerCallPullIfNeeded(controller);
- }
-
- function readableStreamDefaultControllerGetDesiredSize(
- controller,
- ) {
- const stream = controller[sym.controlledReadableStream];
- const state = stream[sym.state];
- if (state === "errored") {
- return null;
- }
- if (state === "closed") {
- return 0;
- }
- return controller[sym.strategyHWM] - controller[sym.queueTotalSize];
- }
-
- function readableStreamDefaultControllerError(
- controller,
- e,
- ) {
- const stream = controller[sym.controlledReadableStream];
- if (stream[sym.state] !== "readable") {
- return;
- }
- resetQueue(controller);
- readableStreamDefaultControllerClearAlgorithms(controller);
- readableStreamError(stream, e);
- }
-
- function readableStreamDefaultControllerHasBackpressure(
- controller,
- ) {
- return readableStreamDefaultControllerShouldCallPull(controller);
- }
-
- function readableStreamDefaultControllerShouldCallPull(
- controller,
- ) {
- const stream = controller[sym.controlledReadableStream];
- if (
- !readableStreamDefaultControllerCanCloseOrEnqueue(controller) ||
- controller[sym.started] === false
- ) {
- return false;
- }
- if (
- isReadableStreamLocked(stream) &&
- readableStreamGetNumReadRequests(stream) > 0
- ) {
- return true;
- }
- const desiredSize = readableStreamDefaultControllerGetDesiredSize(
- controller,
- );
- assert(desiredSize !== null);
- return desiredSize > 0;
- }
-
- function readableStreamDefaultReaderRead(
- reader,
- ) {
- const stream = reader[sym.ownerReadableStream];
- assert(stream);
- stream[sym.disturbed] = true;
- if (stream[sym.state] === "closed") {
- return Promise.resolve(
- readableStreamCreateReadResult(
- undefined,
- true,
- reader[sym.forAuthorCode],
- ),
- );
- }
- if (stream[sym.state] === "errored") {
- return Promise.reject(stream[sym.storedError]);
- }
- assert(stream[sym.state] === "readable");
- return (stream[
- sym.readableStreamController
- ])[sym.pullSteps]();
- }
-
- function readableStreamError(stream, e) {
- assert(isReadableStream(stream));
- assert(stream[sym.state] === "readable");
- stream[sym.state] = "errored";
- stream[sym.storedError] = e;
- const reader = stream[sym.reader];
- if (reader === undefined) {
- return;
- }
- if (isReadableStreamDefaultReader(reader)) {
- for (const readRequest of reader[sym.readRequests]) {
- assert(readRequest.reject);
- readRequest.reject(e);
- readRequest.reject = undefined;
- readRequest.resolve = undefined;
- }
- reader[sym.readRequests] = [];
- }
- // 3.5.6.8 Otherwise, support BYOB Reader
- reader[sym.closedPromise].reject(e);
- reader[sym.closedPromise].reject = undefined;
- reader[sym.closedPromise].resolve = undefined;
- setPromiseIsHandledToTrue(reader[sym.closedPromise].promise);
- }
-
- function readableStreamFulfillReadRequest(
- stream,
- chunk,
- done,
- ) {
- const reader = stream[sym.reader];
- const readRequest = reader[sym.readRequests].shift();
- assert(readRequest.resolve);
- readRequest.resolve(
- readableStreamCreateReadResult(chunk, done, reader[sym.forAuthorCode]),
- );
- }
-
- function readableStreamGetNumReadRequests(
- stream,
- ) {
- return stream[sym.reader]?.[sym.readRequests].length ?? 0;
- }
-
- function readableStreamHasDefaultReader(
- stream,
- ) {
- const reader = stream[sym.reader];
- return !(reader === undefined || !isReadableStreamDefaultReader(reader));
- }
-
- function readableStreamPipeTo(
- source,
- dest,
- preventClose,
- preventAbort,
- preventCancel,
- signal,
- ) {
- assert(isReadableStream(source));
- assert(isWritableStream(dest));
- assert(
- typeof preventClose === "boolean" &&
- typeof preventAbort === "boolean" &&
- typeof preventCancel === "boolean",
- );
- assert(signal === undefined || signal instanceof AbortSignal);
- assert(!isReadableStreamLocked(source));
- assert(!isWritableStreamLocked(dest));
- const reader = acquireReadableStreamDefaultReader(source);
- const writer = acquireWritableStreamDefaultWriter(dest);
- source[sym.disturbed] = true;
- let shuttingDown = false;
- const promise = getDeferred();
- let abortAlgorithm;
- if (signal) {
- abortAlgorithm = () => {
- const error = new DOMException("Abort signal received.", "AbortSignal");
- const actions = [];
- if (!preventAbort) {
- actions.push(() => {
- if (dest[sym.state] === "writable") {
- return writableStreamAbort(dest, error);
- } else {
- return Promise.resolve(undefined);
- }
- });
- }
- if (!preventCancel) {
- actions.push(() => {
- if (source[sym.state] === "readable") {
- return readableStreamCancel(source, error);
- } else {
- return Promise.resolve(undefined);
- }
- });
- }
- shutdownWithAction(
- () => Promise.all(actions.map((action) => action())),
- true,
- error,
- );
- };
- if (signal.aborted) {
- abortAlgorithm();
- return promise.promise;
- }
- signal.addEventListener("abort", abortAlgorithm);
- }
-
- let currentWrite = Promise.resolve();
-
- // At this point, the spec becomes non-specific and vague. Most of the rest
- // of this code is based on the reference implementation that is part of the
- // specification. This is why the functions are only scoped to this function
- // to ensure they don't leak into the spec compliant parts.
-
- function isOrBecomesClosed(
- stream,
- promise,
- action,
- ) {
- if (stream[sym.state] === "closed") {
- action();
- } else {
- setPromiseIsHandledToTrue(promise.then(action));
- }
- }
-
- function isOrBecomesErrored(
- stream,
- promise,
- action,
- ) {
- if (stream[sym.state] === "errored") {
- action(stream[sym.storedError]);
- } else {
- setPromiseIsHandledToTrue(promise.catch((error) => action(error)));
- }
- }
-
- function finalize(isError, error) {
- writableStreamDefaultWriterRelease(writer);
- readableStreamReaderGenericRelease(reader);
-
- if (signal) {
- signal.removeEventListener("abort", abortAlgorithm);
- }
- if (isError) {
- promise.reject(error);
- } else {
- promise.resolve();
- }
- }
-
- function waitForWritesToFinish() {
- const oldCurrentWrite = currentWrite;
- return currentWrite.then(() =>
- oldCurrentWrite !== currentWrite ? waitForWritesToFinish() : undefined
- );
- }
-
- function shutdownWithAction(
- action,
- originalIsError,
- originalError,
- ) {
- function doTheRest() {
- setPromiseIsHandledToTrue(
- action().then(
- () => finalize(originalIsError, originalError),
- (newError) => finalize(true, newError),
- ),
- );
- }
-
- if (shuttingDown) {
- return;
- }
- shuttingDown = true;
-
- if (
- dest[sym.state] === "writable" &&
- writableStreamCloseQueuedOrInFlight(dest) === false
- ) {
- setPromiseIsHandledToTrue(waitForWritesToFinish().then(doTheRest));
- } else {
- doTheRest();
- }
- }
-
- function shutdown(isError, error) {
- if (shuttingDown) {
- return;
- }
- shuttingDown = true;
-
- if (
- dest[sym.state] === "writable" &&
- !writableStreamCloseQueuedOrInFlight(dest)
- ) {
- setPromiseIsHandledToTrue(
- waitForWritesToFinish().then(() => finalize(isError, error)),
- );
- }
- finalize(isError, error);
- }
-
- function pipeStep() {
- if (shuttingDown) {
- return Promise.resolve(true);
- }
- return writer[sym.readyPromise].promise.then(() => {
- return readableStreamDefaultReaderRead(reader).then(
- ({ value, done }) => {
- if (done === true) {
- return true;
- }
- currentWrite = writableStreamDefaultWriterWrite(
- writer,
- value,
- ).then(undefined, () => {});
- return false;
- },
- );
- });
- }
-
- function pipeLoop() {
- return new Promise((resolveLoop, rejectLoop) => {
- function next(done) {
- if (done) {
- resolveLoop(undefined);
- } else {
- setPromiseIsHandledToTrue(pipeStep().then(next, rejectLoop));
- }
- }
- next(false);
- });
- }
-
- isOrBecomesErrored(
- source,
- reader[sym.closedPromise].promise,
- (storedError) => {
- if (!preventAbort) {
- shutdownWithAction(
- () => writableStreamAbort(dest, storedError),
- true,
- storedError,
- );
- } else {
- shutdown(true, storedError);
- }
- },
- );
-
- isOrBecomesErrored(
- dest,
- writer[sym.closedPromise].promise,
- (storedError) => {
- if (!preventCancel) {
- shutdownWithAction(
- () => readableStreamCancel(source, storedError),
- true,
- storedError,
- );
- } else {
- shutdown(true, storedError);
- }
- },
- );
-
- isOrBecomesClosed(source, reader[sym.closedPromise].promise, () => {
- if (!preventClose) {
- shutdownWithAction(() =>
- writableStreamDefaultWriterCloseWithErrorPropagation(writer)
- );
- }
- });
-
- if (
- writableStreamCloseQueuedOrInFlight(dest) ||
- dest[sym.state] === "closed"
- ) {
- const destClosed = new TypeError(
- "The destination writable stream closed before all data could be piped to it.",
- );
- if (!preventCancel) {
- shutdownWithAction(
- () => readableStreamCancel(source, destClosed),
- true,
- destClosed,
- );
- } else {
- shutdown(true, destClosed);
- }
- }
-
- setPromiseIsHandledToTrue(pipeLoop());
- return promise.promise;
- }
-
- function readableStreamReaderGenericCancel(
- reader,
- reason,
- ) {
- const stream = reader[sym.ownerReadableStream];
- assert(stream);
- return readableStreamCancel(stream, reason);
- }
-
- function readableStreamReaderGenericInitialize(
- reader,
- stream,
- ) {
- reader[sym.forAuthorCode] = true;
- reader[sym.ownerReadableStream] = stream;
- stream[sym.reader] = reader;
- if (stream[sym.state] === "readable") {
- reader[sym.closedPromise] = getDeferred();
- } else if (stream[sym.state] === "closed") {
- reader[sym.closedPromise] = { promise: Promise.resolve() };
- } else {
- assert(stream[sym.state] === "errored");
- reader[sym.closedPromise] = {
- promise: Promise.reject(stream[sym.storedError]),
- };
- setPromiseIsHandledToTrue(reader[sym.closedPromise].promise);
- }
- }
-
- function readableStreamReaderGenericRelease(
- reader,
- ) {
- assert(reader[sym.ownerReadableStream]);
- assert(reader[sym.ownerReadableStream][sym.reader] === reader);
- const closedPromise = reader[sym.closedPromise];
- if (reader[sym.ownerReadableStream][sym.state] === "readable") {
- assert(closedPromise.reject);
- closedPromise.reject(new TypeError("ReadableStream state is readable."));
- } else {
- closedPromise.promise = Promise.reject(
- new TypeError("Reading is closed."),
- );
- delete closedPromise.reject;
- delete closedPromise.resolve;
- }
- setPromiseIsHandledToTrue(closedPromise.promise);
- reader[sym.ownerReadableStream][sym.reader] = undefined;
- reader[sym.ownerReadableStream] = undefined;
- }
-
- function readableStreamTee(
- stream,
- cloneForBranch2,
- ) {
- assert(isReadableStream(stream));
- assert(typeof cloneForBranch2 === "boolean");
- const reader = acquireReadableStreamDefaultReader(stream);
- let reading = false;
- let canceled1 = false;
- let canceled2 = false;
- let reason1 = undefined;
- let reason2 = undefined;
- /* eslint-disable prefer-const */
- let branch1;
- let branch2;
- /* eslint-enable prefer-const */
- const cancelPromise = getDeferred();
- const pullAlgorithm = () => {
- if (reading) {
- return Promise.resolve();
- }
- reading = true;
- const readPromise = readableStreamDefaultReaderRead(reader).then(
- (result) => {
- reading = false;
- assert(typeof result === "object");
- const { done } = result;
- assert(typeof done === "boolean");
- if (done) {
- if (!canceled1) {
- readableStreamDefaultControllerClose(
- branch1[
- sym.readableStreamController
- ],
- );
- }
- if (!canceled2) {
- readableStreamDefaultControllerClose(
- branch2[
- sym.readableStreamController
- ],
- );
- }
- return;
- }
- const { value } = result;
- const value1 = value;
- let value2 = value;
- if (!canceled2 && cloneForBranch2) {
- value2 = cloneValue(value2);
- }
- if (!canceled1) {
- readableStreamDefaultControllerEnqueue(
- branch1[
- sym.readableStreamController
- ],
- value1,
- );
- }
- if (!canceled2) {
- readableStreamDefaultControllerEnqueue(
- branch2[
- sym.readableStreamController
- ],
- value2,
- );
- }
- },
- );
- setPromiseIsHandledToTrue(readPromise);
- return Promise.resolve();
- };
- const cancel1Algorithm = (reason) => {
- canceled1 = true;
- reason1 = reason;
- if (canceled2) {
- const compositeReason = [reason1, reason2];
- const cancelResult = readableStreamCancel(stream, compositeReason);
- cancelPromise.resolve(cancelResult);
- }
- return cancelPromise.promise;
- };
- const cancel2Algorithm = (reason) => {
- canceled2 = true;
- reason2 = reason;
- if (canceled1) {
- const compositeReason = [reason1, reason2];
- const cancelResult = readableStreamCancel(stream, compositeReason);
- cancelPromise.resolve(cancelResult);
- }
- return cancelPromise.promise;
- };
- const startAlgorithm = () => undefined;
- branch1 = createReadableStream(
- startAlgorithm,
- pullAlgorithm,
- cancel1Algorithm,
- );
- branch2 = createReadableStream(
- startAlgorithm,
- pullAlgorithm,
- cancel2Algorithm,
- );
- setPromiseIsHandledToTrue(
- reader[sym.closedPromise].promise.catch((r) => {
- readableStreamDefaultControllerError(
- branch1[
- sym.readableStreamController
- ],
- r,
- );
- readableStreamDefaultControllerError(
- branch2[
- sym.readableStreamController
- ],
- r,
- );
- }),
- );
- return [branch1, branch2];
- }
-
- function resetQueue(container) {
- assert(sym.queue in container && sym.queueTotalSize in container);
- container[sym.queue] = [];
- container[sym.queueTotalSize] = 0;
- }
-
- /** An internal function which mimics the behavior of setting the promise to
- * handled in JavaScript. In this situation, an assertion failure, which
- * shouldn't happen will get thrown, instead of swallowed. */
- function setPromiseIsHandledToTrue(promise) {
- promise.then(undefined, (e) => {
- if (e && e instanceof AssertionError) {
- queueMicrotask(() => {
- throw e;
- });
- }
- });
- }
-
- function setUpReadableByteStreamController(
- stream,
- controller,
- startAlgorithm,
- pullAlgorithm,
- cancelAlgorithm,
- highWaterMark,
- autoAllocateChunkSize,
- ) {
- assert(stream[sym.readableStreamController] === undefined);
- if (autoAllocateChunkSize !== undefined) {
- assert(Number.isInteger(autoAllocateChunkSize));
- assert(autoAllocateChunkSize >= 0);
- }
- controller[sym.controlledReadableByteStream] = stream;
- controller[sym.pulling] = controller[sym.pullAgain] = false;
- controller[sym.byobRequest] = undefined;
- controller[sym.queue] = [];
- controller[sym.queueTotalSize] = 0;
- controller[sym.closeRequested] = controller[sym.started] = false;
- controller[sym.strategyHWM] = validateAndNormalizeHighWaterMark(
- highWaterMark,
- );
- controller[sym.pullAlgorithm] = pullAlgorithm;
- controller[sym.cancelAlgorithm] = cancelAlgorithm;
- controller[sym.autoAllocateChunkSize] = autoAllocateChunkSize;
- // 3.13.26.12 Set controller.[[pendingPullIntos]] to a new empty List.
- stream[sym.readableStreamController] = controller;
- const startResult = startAlgorithm();
- const startPromise = Promise.resolve(startResult);
- setPromiseIsHandledToTrue(
- startPromise.then(
- () => {
- controller[sym.started] = true;
- assert(!controller[sym.pulling]);
- assert(!controller[sym.pullAgain]);
- readableByteStreamControllerCallPullIfNeeded(controller);
- },
- (r) => {
- readableByteStreamControllerError(controller, r);
- },
- ),
- );
- }
-
- function setUpReadableByteStreamControllerFromUnderlyingSource(
- stream,
- underlyingByteSource,
- highWaterMark,
- ) {
- assert(underlyingByteSource);
- const controller = Object.create(
- ReadableByteStreamController.prototype,
- );
- const startAlgorithm = () => {
- return invokeOrNoop(underlyingByteSource, "start", controller);
- };
- const pullAlgorithm = createAlgorithmFromUnderlyingMethod(
- underlyingByteSource,
- "pull",
- 0,
- controller,
- );
- setFunctionName(pullAlgorithm, "[[pullAlgorithm]]");
- const cancelAlgorithm = createAlgorithmFromUnderlyingMethod(
- underlyingByteSource,
- "cancel",
- 1,
- );
- setFunctionName(cancelAlgorithm, "[[cancelAlgorithm]]");
- // 3.13.27.6 Let autoAllocateChunkSize be ? GetV(underlyingByteSource, "autoAllocateChunkSize").
- const autoAllocateChunkSize = undefined;
- setUpReadableByteStreamController(
- stream,
- controller,
- startAlgorithm,
- pullAlgorithm,
- cancelAlgorithm,
- highWaterMark,
- autoAllocateChunkSize,
- );
- }
-
- function setUpReadableStreamDefaultController(
- stream,
- controller,
- startAlgorithm,
- pullAlgorithm,
- cancelAlgorithm,
- highWaterMark,
- sizeAlgorithm,
- ) {
- assert(stream[sym.readableStreamController] === undefined);
- controller[sym.controlledReadableStream] = stream;
- controller[sym.queue] = [];
- controller[sym.queueTotalSize] = 0;
- controller[sym.started] = controller[sym.closeRequested] = controller[
- sym.pullAgain
- ] = controller[sym.pulling] = false;
- controller[sym.strategySizeAlgorithm] = sizeAlgorithm;
- controller[sym.strategyHWM] = highWaterMark;
- controller[sym.pullAlgorithm] = pullAlgorithm;
- controller[sym.cancelAlgorithm] = cancelAlgorithm;
- stream[sym.readableStreamController] = controller;
- const startResult = startAlgorithm();
- const startPromise = Promise.resolve(startResult);
- setPromiseIsHandledToTrue(
- startPromise.then(
- () => {
- controller[sym.started] = true;
- assert(controller[sym.pulling] === false);
- assert(controller[sym.pullAgain] === false);
- readableStreamDefaultControllerCallPullIfNeeded(controller);
- },
- (r) => {
- readableStreamDefaultControllerError(controller, r);
- },
- ),
- );
- }
-
- function setUpReadableStreamDefaultControllerFromUnderlyingSource(
- stream,
- underlyingSource,
- highWaterMark,
- sizeAlgorithm,
- ) {
- assert(underlyingSource);
- const controller = Object.create(
- ReadableStreamDefaultController.prototype,
- );
- const startAlgorithm = () =>
- invokeOrNoop(underlyingSource, "start", controller);
- const pullAlgorithm = createAlgorithmFromUnderlyingMethod(
- underlyingSource,
- "pull",
- 0,
- controller,
- );
- setFunctionName(pullAlgorithm, "[[pullAlgorithm]]");
- const cancelAlgorithm = createAlgorithmFromUnderlyingMethod(
- underlyingSource,
- "cancel",
- 1,
- );
- setFunctionName(cancelAlgorithm, "[[cancelAlgorithm]]");
- setUpReadableStreamDefaultController(
- stream,
- controller,
- startAlgorithm,
- pullAlgorithm,
- cancelAlgorithm,
- highWaterMark,
- sizeAlgorithm,
- );
- }
-
- function setUpTransformStreamDefaultController(
- stream,
- controller,
- transformAlgorithm,
- flushAlgorithm,
- ) {
- assert(isTransformStream(stream));
- assert(stream[sym.transformStreamController] === undefined);
- controller[sym.controlledTransformStream] = stream;
- stream[sym.transformStreamController] = controller;
- controller[sym.transformAlgorithm] = transformAlgorithm;
- controller[sym.flushAlgorithm] = flushAlgorithm;
- }
-
- function setUpTransformStreamDefaultControllerFromTransformer(
- stream,
- transformer,
- ) {
- assert(transformer);
- const controller = Object.create(
- TransformStreamDefaultController.prototype,
- );
- let transformAlgorithm = (chunk) => {
- try {
- transformStreamDefaultControllerEnqueue(
- controller,
- // it defaults to no tranformation, so I is assumed to be O
- chunk,
- );
- } catch (e) {
- return Promise.reject(e);
- }
- return Promise.resolve();
- };
- const transformMethod = transformer.transform;
- if (transformMethod) {
- if (typeof transformMethod !== "function") {
- throw new TypeError("tranformer.transform must be callable.");
- }
- transformAlgorithm = async (chunk) =>
- call(transformMethod, transformer, [chunk, controller]);
- }
- const flushAlgorithm = createAlgorithmFromUnderlyingMethod(
- transformer,
- "flush",
- 0,
- controller,
- );
- setUpTransformStreamDefaultController(
- stream,
- controller,
- transformAlgorithm,
- flushAlgorithm,
- );
- }
-
- function setUpWritableStreamDefaultController(
- stream,
- controller,
- startAlgorithm,
- writeAlgorithm,
- closeAlgorithm,
- abortAlgorithm,
- highWaterMark,
- sizeAlgorithm,
- ) {
- assert(isWritableStream(stream));
- assert(stream[sym.writableStreamController] === undefined);
- controller[sym.controlledWritableStream] = stream;
- stream[sym.writableStreamController] = controller;
- controller[sym.queue] = [];
- controller[sym.queueTotalSize] = 0;
- controller[sym.started] = false;
- controller[sym.strategySizeAlgorithm] = sizeAlgorithm;
- controller[sym.strategyHWM] = highWaterMark;
- controller[sym.writeAlgorithm] = writeAlgorithm;
- controller[sym.closeAlgorithm] = closeAlgorithm;
- controller[sym.abortAlgorithm] = abortAlgorithm;
- const backpressure = writableStreamDefaultControllerGetBackpressure(
- controller,
- );
- writableStreamUpdateBackpressure(stream, backpressure);
- const startResult = startAlgorithm();
- const startPromise = Promise.resolve(startResult);
- setPromiseIsHandledToTrue(
- startPromise.then(
- () => {
- assert(
- stream[sym.state] === "writable" ||
- stream[sym.state] === "erroring",
- );
- controller[sym.started] = true;
- writableStreamDefaultControllerAdvanceQueueIfNeeded(controller);
- },
- (r) => {
- assert(
- stream[sym.state] === "writable" ||
- stream[sym.state] === "erroring",
- );
- controller[sym.started] = true;
- writableStreamDealWithRejection(stream, r);
- },
- ),
- );
- }
-
- function setUpWritableStreamDefaultControllerFromUnderlyingSink(
- stream,
- underlyingSink,
- highWaterMark,
- sizeAlgorithm,
- ) {
- assert(underlyingSink);
- const controller = Object.create(
- WritableStreamDefaultController.prototype,
- );
- const startAlgorithm = () => {
- return invokeOrNoop(underlyingSink, "start", controller);
- };
- const writeAlgorithm = createAlgorithmFromUnderlyingMethod(
- underlyingSink,
- "write",
- 1,
- controller,
- );
- setFunctionName(writeAlgorithm, "[[writeAlgorithm]]");
- const closeAlgorithm = createAlgorithmFromUnderlyingMethod(
- underlyingSink,
- "close",
- 0,
- );
- setFunctionName(closeAlgorithm, "[[closeAlgorithm]]");
- const abortAlgorithm = createAlgorithmFromUnderlyingMethod(
- underlyingSink,
- "abort",
- 1,
- );
- setFunctionName(abortAlgorithm, "[[abortAlgorithm]]");
- setUpWritableStreamDefaultController(
- stream,
- controller,
- startAlgorithm,
- writeAlgorithm,
- closeAlgorithm,
- abortAlgorithm,
- highWaterMark,
- sizeAlgorithm,
- );
- }
-
- function transformStreamDefaultControllerClearAlgorithms(
- controller,
- ) {
- controller[sym.transformAlgorithm] = undefined;
- controller[sym.flushAlgorithm] = undefined;
- }
-
- function transformStreamDefaultControllerEnqueue(
- controller,
- chunk,
- ) {
- const stream = controller[sym.controlledTransformStream];
- const readableController = stream[sym.readable][
- sym.readableStreamController
- ];
- if (!readableStreamDefaultControllerCanCloseOrEnqueue(readableController)) {
- throw new TypeError(
- "TransformStream's readable controller cannot be closed or enqueued.",
- );
- }
- try {
- readableStreamDefaultControllerEnqueue(readableController, chunk);
- } catch (e) {
- transformStreamErrorWritableAndUnblockWrite(stream, e);
- throw stream[sym.readable][sym.storedError];
- }
- const backpressure = readableStreamDefaultControllerHasBackpressure(
- readableController,
- );
- if (backpressure) {
- transformStreamSetBackpressure(stream, true);
- }
- }
-
- function transformStreamDefaultControllerError(
- controller,
- e,
- ) {
- transformStreamError(controller[sym.controlledTransformStream], e);
- }
-
- function transformStreamDefaultControllerPerformTransform(
- controller,
- chunk,
- ) {
- const transformPromise = controller[sym.transformAlgorithm](chunk);
- return transformPromise.then(undefined, (r) => {
- transformStreamError(controller[sym.controlledTransformStream], r);
- throw r;
- });
- }
-
- function transformStreamDefaultSinkAbortAlgorithm(
- stream,
- reason,
- ) {
- transformStreamError(stream, reason);
- return Promise.resolve(undefined);
- }
-
- function transformStreamDefaultSinkCloseAlgorithm(
- stream,
- ) {
- const readable = stream[sym.readable];
- const controller = stream[sym.transformStreamController];
- const flushPromise = controller[sym.flushAlgorithm]();
- transformStreamDefaultControllerClearAlgorithms(controller);
- return flushPromise.then(
- () => {
- if (readable[sym.state] === "errored") {
- throw readable[sym.storedError];
- }
- const readableController = readable[
- sym.readableStreamController
- ];
- if (
- readableStreamDefaultControllerCanCloseOrEnqueue(readableController)
- ) {
- readableStreamDefaultControllerClose(readableController);
- }
- },
- (r) => {
- transformStreamError(stream, r);
- throw readable[sym.storedError];
- },
- );
- }
-
- function transformStreamDefaultSinkWriteAlgorithm(
- stream,
- chunk,
- ) {
- assert(stream[sym.writable][sym.state] === "writable");
- const controller = stream[sym.transformStreamController];
- if (stream[sym.backpressure]) {
- const backpressureChangePromise = stream[sym.backpressureChangePromise];
- assert(backpressureChangePromise);
- return backpressureChangePromise.promise.then(() => {
- const writable = stream[sym.writable];
- const state = writable[sym.state];
- if (state === "erroring") {
- throw writable[sym.storedError];
- }
- assert(state === "writable");
- return transformStreamDefaultControllerPerformTransform(
- controller,
- chunk,
- );
- });
- }
- return transformStreamDefaultControllerPerformTransform(controller, chunk);
- }
-
- function transformStreamDefaultSourcePullAlgorithm(
- stream,
- ) {
- assert(stream[sym.backpressure] === true);
- assert(stream[sym.backpressureChangePromise] !== undefined);
- transformStreamSetBackpressure(stream, false);
- return stream[sym.backpressureChangePromise].promise;
- }
-
- function transformStreamError(
- stream,
- e,
- ) {
- readableStreamDefaultControllerError(
- stream[sym.readable][
- sym.readableStreamController
- ],
- e,
- );
- transformStreamErrorWritableAndUnblockWrite(stream, e);
- }
-
- function transformStreamDefaultControllerTerminate(
- controller,
- ) {
- const stream = controller[sym.controlledTransformStream];
- const readableController = stream[sym.readable][
- sym.readableStreamController
- ];
- readableStreamDefaultControllerClose(readableController);
- const error = new TypeError("TransformStream is closed.");
- transformStreamErrorWritableAndUnblockWrite(stream, error);
- }
-
- function transformStreamErrorWritableAndUnblockWrite(
- stream,
- e,
- ) {
- transformStreamDefaultControllerClearAlgorithms(
- stream[sym.transformStreamController],
- );
- writableStreamDefaultControllerErrorIfNeeded(
- stream[sym.writable][sym.writableStreamController],
- e,
- );
- if (stream[sym.backpressure]) {
- transformStreamSetBackpressure(stream, false);
- }
- }
-
- function transformStreamSetBackpressure(
- stream,
- backpressure,
- ) {
- assert(stream[sym.backpressure] !== backpressure);
- if (stream[sym.backpressureChangePromise] !== undefined) {
- stream[sym.backpressureChangePromise].resolve(undefined);
- }
- stream[sym.backpressureChangePromise] = getDeferred();
- stream[sym.backpressure] = backpressure;
- }
-
- function transferArrayBuffer(buffer) {
- assert(!isDetachedBuffer(buffer));
- const transferredIshVersion = buffer.slice(0);
-
- Object.defineProperty(buffer, "byteLength", {
- get() {
- return 0;
- },
- });
- buffer[sym.isFakeDetached] = true;
-
- return transferredIshVersion;
- }
-
- function validateAndNormalizeHighWaterMark(
- highWaterMark,
- ) {
- highWaterMark = Number(highWaterMark);
- if (Number.isNaN(highWaterMark) || highWaterMark < 0) {
- throw new RangeError(
- `highWaterMark must be a positive number or Infinity. Received: ${highWaterMark}.`,
- );
- }
- return highWaterMark;
- }
-
- function writableStreamAbort(
- stream,
- reason,
- ) {
- const state = stream[sym.state];
- if (state === "closed" || state === "errored") {
- return Promise.resolve(undefined);
- }
- if (stream[sym.pendingAbortRequest]) {
- return stream[sym.pendingAbortRequest].promise.promise;
- }
- assert(state === "writable" || state === "erroring");
- let wasAlreadyErroring = false;
- if (state === "erroring") {
- wasAlreadyErroring = true;
- reason = undefined;
- }
- const promise = getDeferred();
- stream[sym.pendingAbortRequest] = { promise, reason, wasAlreadyErroring };
-
- if (wasAlreadyErroring === false) {
- writableStreamStartErroring(stream, reason);
- }
- return promise.promise;
- }
-
- function writableStreamAddWriteRequest(
- stream,
- ) {
- assert(isWritableStream(stream));
- assert(stream[sym.state] === "writable");
- const promise = getDeferred();
- stream[sym.writeRequests].push(promise);
- return promise.promise;
- }
-
- function writableStreamClose(
- stream,
- ) {
- const state = stream[sym.state];
- if (state === "closed" || state === "errored") {
- return Promise.reject(
- new TypeError(
- "Cannot close an already closed or errored WritableStream.",
- ),
- );
- }
- assert(!writableStreamCloseQueuedOrInFlight(stream));
- const promise = getDeferred();
- stream[sym.closeRequest] = promise;
- const writer = stream[sym.writer];
- if (writer && stream[sym.backpressure] && state === "writable") {
- writer[sym.readyPromise].resolve();
- writer[sym.readyPromise].resolve = undefined;
- writer[sym.readyPromise].reject = undefined;
- }
- writableStreamDefaultControllerClose(stream[sym.writableStreamController]);
- return promise.promise;
- }
-
- function writableStreamCloseQueuedOrInFlight(
- stream,
- ) {
- return !(
- stream[sym.closeRequest] === undefined &&
- stream[sym.inFlightCloseRequest] === undefined
- );
- }
-
- function writableStreamDealWithRejection(
- stream,
- error,
- ) {
- const state = stream[sym.state];
- if (state === "writable") {
- writableStreamStartErroring(stream, error);
- return;
- }
- assert(state === "erroring");
- writableStreamFinishErroring(stream);
- }
-
- function writableStreamDefaultControllerAdvanceQueueIfNeeded(
- controller,
- ) {
- const stream = controller[sym.controlledWritableStream];
- if (!controller[sym.started]) {
- return;
- }
- if (stream[sym.inFlightWriteRequest]) {
- return;
- }
- const state = stream[sym.state];
- assert(state !== "closed" && state !== "errored");
- if (state === "erroring") {
- writableStreamFinishErroring(stream);
- return;
- }
- if (!controller[sym.queue].length) {
- return;
- }
- const writeRecord = peekQueueValue(controller);
- if (writeRecord === "close") {
- writableStreamDefaultControllerProcessClose(controller);
- } else {
- writableStreamDefaultControllerProcessWrite(
- controller,
- writeRecord.chunk,
- );
- }
- }
-
- function writableStreamDefaultControllerClearAlgorithms(
- controller,
- ) {
- controller[sym.writeAlgorithm] = undefined;
- controller[sym.closeAlgorithm] = undefined;
- controller[sym.abortAlgorithm] = undefined;
- controller[sym.strategySizeAlgorithm] = undefined;
- }
-
- function writableStreamDefaultControllerClose(
- controller,
- ) {
- enqueueValueWithSize(controller, "close", 0);
- writableStreamDefaultControllerAdvanceQueueIfNeeded(controller);
- }
-
- function writableStreamDefaultControllerError(
- controller,
- error,
- ) {
- const stream = controller[sym.controlledWritableStream];
- assert(stream[sym.state] === "writable");
- writableStreamDefaultControllerClearAlgorithms(controller);
- writableStreamStartErroring(stream, error);
- }
-
- function writableStreamDefaultControllerErrorIfNeeded(
- controller,
- error,
- ) {
- if (controller[sym.controlledWritableStream][sym.state] === "writable") {
- writableStreamDefaultControllerError(controller, error);
- }
- }
-
- function writableStreamDefaultControllerGetBackpressure(
- controller,
- ) {
- const desiredSize = writableStreamDefaultControllerGetDesiredSize(
- controller,
- );
- return desiredSize <= 0;
- }
-
- function writableStreamDefaultControllerGetChunkSize(
- controller,
- chunk,
- ) {
- let returnValue;
- try {
- returnValue = controller[sym.strategySizeAlgorithm](chunk);
- } catch (e) {
- writableStreamDefaultControllerErrorIfNeeded(controller, e);
- return 1;
- }
- return returnValue;
- }
-
- function writableStreamDefaultControllerGetDesiredSize(
- controller,
- ) {
- return controller[sym.strategyHWM] - controller[sym.queueTotalSize];
- }
-
- function writableStreamDefaultControllerProcessClose(
- controller,
- ) {
- const stream = controller[sym.controlledWritableStream];
- writableStreamMarkCloseRequestInFlight(stream);
- dequeueValue(controller);
- assert(controller[sym.queue].length === 0);
- const sinkClosePromise = controller[sym.closeAlgorithm]();
- writableStreamDefaultControllerClearAlgorithms(controller);
- setPromiseIsHandledToTrue(
- sinkClosePromise.then(
- () => {
- writableStreamFinishInFlightClose(stream);
- },
- (reason) => {
- writableStreamFinishInFlightCloseWithError(stream, reason);
- },
- ),
- );
- }
-
- function writableStreamDefaultControllerProcessWrite(
- controller,
- chunk,
- ) {
- const stream = controller[sym.controlledWritableStream];
- writableStreamMarkFirstWriteRequestInFlight(stream);
- const sinkWritePromise = controller[sym.writeAlgorithm](chunk);
- setPromiseIsHandledToTrue(
- sinkWritePromise.then(
- () => {
- writableStreamFinishInFlightWrite(stream);
- const state = stream[sym.state];
- assert(state === "writable" || state === "erroring");
- dequeueValue(controller);
- if (
- !writableStreamCloseQueuedOrInFlight(stream) &&
- state === "writable"
- ) {
- const backpressure = writableStreamDefaultControllerGetBackpressure(
- controller,
- );
- writableStreamUpdateBackpressure(stream, backpressure);
- }
- writableStreamDefaultControllerAdvanceQueueIfNeeded(controller);
- },
- (reason) => {
- if (stream[sym.state] === "writable") {
- writableStreamDefaultControllerClearAlgorithms(controller);
- }
- writableStreamFinishInFlightWriteWithError(stream, reason);
- },
- ),
- );
- }
-
- function writableStreamDefaultControllerWrite(
- controller,
- chunk,
- chunkSize,
- ) {
- const writeRecord = { chunk };
- try {
- enqueueValueWithSize(controller, writeRecord, chunkSize);
- } catch (e) {
- writableStreamDefaultControllerErrorIfNeeded(controller, e);
- return;
- }
- const stream = controller[sym.controlledWritableStream];
- if (
- !writableStreamCloseQueuedOrInFlight(stream) &&
- stream[sym.state] === "writable"
- ) {
- const backpressure = writableStreamDefaultControllerGetBackpressure(
- controller,
- );
- writableStreamUpdateBackpressure(stream, backpressure);
- }
- writableStreamDefaultControllerAdvanceQueueIfNeeded(controller);
- }
-
- function writableStreamDefaultWriterAbort(
- writer,
- reason,
- ) {
- const stream = writer[sym.ownerWritableStream];
- assert(stream);
- return writableStreamAbort(stream, reason);
- }
-
- function writableStreamDefaultWriterClose(
- writer,
- ) {
- const stream = writer[sym.ownerWritableStream];
- assert(stream);
- return writableStreamClose(stream);
- }
-
- function writableStreamDefaultWriterCloseWithErrorPropagation(
- writer,
- ) {
- const stream = writer[sym.ownerWritableStream];
- assert(stream);
- const state = stream[sym.state];
- if (writableStreamCloseQueuedOrInFlight(stream) || state === "closed") {
- return Promise.resolve();
- }
- if (state === "errored") {
- return Promise.reject(stream[sym.storedError]);
- }
- assert(state === "writable" || state === "erroring");
- return writableStreamDefaultWriterClose(writer);
- }
-
- function writableStreamDefaultWriterEnsureClosePromiseRejected(
- writer,
- error,
- ) {
- if (writer[sym.closedPromise].reject) {
- writer[sym.closedPromise].reject(error);
- } else {
- writer[sym.closedPromise] = {
- promise: Promise.reject(error),
- };
- }
- setPromiseIsHandledToTrue(writer[sym.closedPromise].promise);
- }
-
- function writableStreamDefaultWriterEnsureReadyPromiseRejected(
- writer,
- error,
- ) {
- if (writer[sym.readyPromise].reject) {
- writer[sym.readyPromise].reject(error);
- writer[sym.readyPromise].reject = undefined;
- writer[sym.readyPromise].resolve = undefined;
- } else {
- writer[sym.readyPromise] = {
- promise: Promise.reject(error),
- };
- }
- setPromiseIsHandledToTrue(writer[sym.readyPromise].promise);
- }
-
- function writableStreamDefaultWriterWrite(
- writer,
- chunk,
- ) {
- const stream = writer[sym.ownerWritableStream];
- assert(stream);
- const controller = stream[sym.writableStreamController];
- assert(controller);
- const chunkSize = writableStreamDefaultControllerGetChunkSize(
- controller,
- chunk,
- );
- if (stream !== writer[sym.ownerWritableStream]) {
- return Promise.reject("Writer has incorrect WritableStream.");
- }
- const state = stream[sym.state];
- if (state === "errored") {
- return Promise.reject(stream[sym.storedError]);
- }
- if (writableStreamCloseQueuedOrInFlight(stream) || state === "closed") {
- return Promise.reject(new TypeError("The stream is closed or closing."));
- }
- if (state === "erroring") {
- return Promise.reject(stream[sym.storedError]);
- }
- assert(state === "writable");
- const promise = writableStreamAddWriteRequest(stream);
- writableStreamDefaultControllerWrite(controller, chunk, chunkSize);
- return promise;
- }
-
- function writableStreamDefaultWriterGetDesiredSize(
- writer,
- ) {
- const stream = writer[sym.ownerWritableStream];
- const state = stream[sym.state];
- if (state === "errored" || state === "erroring") {
- return null;
- }
- if (state === "closed") {
- return 0;
- }
- return writableStreamDefaultControllerGetDesiredSize(
- stream[sym.writableStreamController],
- );
- }
-
- function writableStreamDefaultWriterRelease(
- writer,
- ) {
- const stream = writer[sym.ownerWritableStream];
- assert(stream);
- assert(stream[sym.writer] === writer);
- const releasedError = new TypeError(
- "Writer was released and can no longer be used to monitor the stream's closedness.",
- );
- writableStreamDefaultWriterEnsureReadyPromiseRejected(
- writer,
- releasedError,
- );
- writableStreamDefaultWriterEnsureClosePromiseRejected(
- writer,
- releasedError,
- );
- stream[sym.writer] = undefined;
- writer[sym.ownerWritableStream] = undefined;
- }
-
- function writableStreamFinishErroring(stream) {
- assert(stream[sym.state] === "erroring");
- assert(!writableStreamHasOperationMarkedInFlight(stream));
- stream[sym.state] = "errored";
- stream[sym.writableStreamController][sym.errorSteps]();
- const storedError = stream[sym.storedError];
- for (const writeRequest of stream[sym.writeRequests]) {
- assert(writeRequest.reject);
- writeRequest.reject(storedError);
- }
- stream[sym.writeRequests] = [];
- if (!stream[sym.pendingAbortRequest]) {
- writableStreamRejectCloseAndClosedPromiseIfNeeded(stream);
- return;
- }
- const abortRequest = stream[sym.pendingAbortRequest];
- assert(abortRequest);
- stream[sym.pendingAbortRequest] = undefined;
- if (abortRequest.wasAlreadyErroring) {
- assert(abortRequest.promise.reject);
- abortRequest.promise.reject(storedError);
- writableStreamRejectCloseAndClosedPromiseIfNeeded(stream);
- return;
- }
- const promise = stream[sym.writableStreamController][sym.abortSteps](
- abortRequest.reason,
- );
- setPromiseIsHandledToTrue(
- promise.then(
- () => {
- assert(abortRequest.promise.resolve);
- abortRequest.promise.resolve();
- writableStreamRejectCloseAndClosedPromiseIfNeeded(stream);
- },
- (reason) => {
- assert(abortRequest.promise.reject);
- abortRequest.promise.reject(reason);
- writableStreamRejectCloseAndClosedPromiseIfNeeded(stream);
- },
- ),
- );
- }
-
- function writableStreamFinishInFlightClose(
- stream,
- ) {
- assert(stream[sym.inFlightCloseRequest]);
- stream[sym.inFlightCloseRequest]?.resolve();
- stream[sym.inFlightCloseRequest] = undefined;
- const state = stream[sym.state];
- assert(state === "writable" || state === "erroring");
- if (state === "erroring") {
- stream[sym.storedError] = undefined;
- if (stream[sym.pendingAbortRequest]) {
- stream[sym.pendingAbortRequest].promise.resolve();
- stream[sym.pendingAbortRequest] = undefined;
- }
- }
- stream[sym.state] = "closed";
- const writer = stream[sym.writer];
- if (writer) {
- writer[sym.closedPromise].resolve();
- }
- assert(stream[sym.pendingAbortRequest] === undefined);
- assert(stream[sym.storedError] === undefined);
- }
-
- function writableStreamFinishInFlightCloseWithError(
- stream,
- error,
- ) {
- assert(stream[sym.inFlightCloseRequest]);
- stream[sym.inFlightCloseRequest]?.reject(error);
- stream[sym.inFlightCloseRequest] = undefined;
- assert(
- stream[sym.state] === "writable" || stream[sym.state] === "erroring",
- );
- if (stream[sym.pendingAbortRequest]) {
- stream[sym.pendingAbortRequest]?.promise.reject(error);
- stream[sym.pendingAbortRequest] = undefined;
- }
- writableStreamDealWithRejection(stream, error);
- }
-
- function writableStreamFinishInFlightWrite(
- stream,
- ) {
- assert(stream[sym.inFlightWriteRequest]);
- stream[sym.inFlightWriteRequest].resolve();
- stream[sym.inFlightWriteRequest] = undefined;
- }
-
- function writableStreamFinishInFlightWriteWithError(
- stream,
- error,
- ) {
- assert(stream[sym.inFlightWriteRequest]);
- stream[sym.inFlightWriteRequest].reject(error);
- stream[sym.inFlightWriteRequest] = undefined;
- assert(
- stream[sym.state] === "writable" || stream[sym.state] === "erroring",
- );
- writableStreamDealWithRejection(stream, error);
- }
-
- function writableStreamHasOperationMarkedInFlight(
- stream,
- ) {
- return !(
- stream[sym.inFlightWriteRequest] === undefined &&
- stream[sym.inFlightCloseRequest] === undefined
- );
- }
-
- function writableStreamMarkCloseRequestInFlight(
- stream,
- ) {
- assert(stream[sym.inFlightCloseRequest] === undefined);
- assert(stream[sym.closeRequest] !== undefined);
- stream[sym.inFlightCloseRequest] = stream[sym.closeRequest];
- stream[sym.closeRequest] = undefined;
- }
-
- function writableStreamMarkFirstWriteRequestInFlight(
- stream,
- ) {
- assert(stream[sym.inFlightWriteRequest] === undefined);
- assert(stream[sym.writeRequests].length);
- const writeRequest = stream[sym.writeRequests].shift();
- stream[sym.inFlightWriteRequest] = writeRequest;
- }
-
- function writableStreamRejectCloseAndClosedPromiseIfNeeded(
- stream,
- ) {
- assert(stream[sym.state] === "errored");
- if (stream[sym.closeRequest]) {
- assert(stream[sym.inFlightCloseRequest] === undefined);
- stream[sym.closeRequest].reject(stream[sym.storedError]);
- stream[sym.closeRequest] = undefined;
- }
- const writer = stream[sym.writer];
- if (writer) {
- writer[sym.closedPromise].reject(stream[sym.storedError]);
- setPromiseIsHandledToTrue(writer[sym.closedPromise].promise);
- }
- }
-
- function writableStreamStartErroring(
- stream,
- reason,
- ) {
- assert(stream[sym.storedError] === undefined);
- assert(stream[sym.state] === "writable");
- const controller = stream[sym.writableStreamController];
- assert(controller);
- stream[sym.state] = "erroring";
- stream[sym.storedError] = reason;
- const writer = stream[sym.writer];
- if (writer) {
- writableStreamDefaultWriterEnsureReadyPromiseRejected(writer, reason);
- }
- if (
- !writableStreamHasOperationMarkedInFlight(stream) &&
- controller[sym.started]
- ) {
- writableStreamFinishErroring(stream);
- }
- }
-
- function writableStreamUpdateBackpressure(
- stream,
- backpressure,
- ) {
- assert(stream[sym.state] === "writable");
- assert(!writableStreamCloseQueuedOrInFlight(stream));
- const writer = stream[sym.writer];
- if (writer && backpressure !== stream[sym.backpressure]) {
- if (backpressure) {
- writer[sym.readyPromise] = getDeferred();
- } else {
- assert(backpressure === false);
- writer[sym.readyPromise].resolve();
- writer[sym.readyPromise].resolve = undefined;
- writer[sym.readyPromise].reject = undefined;
- }
- }
- stream[sym.backpressure] = backpressure;
- }
- /* eslint-enable */
-
- window.__bootstrap.streams = {
- ReadableStream,
- TransformStream,
- WritableStream,
- isReadableStreamDisturbed,
- };
-})(this);
diff --git a/cli/rt/20_blob.js b/cli/rt/20_blob.js
deleted file mode 100644
index f7309dafb..000000000
--- a/cli/rt/20_blob.js
+++ /dev/null
@@ -1,223 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-((window) => {
- const { build } = window.__bootstrap.build;
- const { ReadableStream } = window.__bootstrap.streams;
-
- const bytesSymbol = Symbol("bytes");
-
- function containsOnlyASCII(str) {
- if (typeof str !== "string") {
- return false;
- }
- return /^[\x00-\x7F]*$/.test(str);
- }
-
- function convertLineEndingsToNative(s) {
- const nativeLineEnd = build.os == "windows" ? "\r\n" : "\n";
-
- let position = 0;
-
- let collectionResult = collectSequenceNotCRLF(s, position);
-
- let token = collectionResult.collected;
- position = collectionResult.newPosition;
-
- let result = token;
-
- while (position < s.length) {
- const c = s.charAt(position);
- if (c == "\r") {
- result += nativeLineEnd;
- position++;
- if (position < s.length && s.charAt(position) == "\n") {
- position++;
- }
- } else if (c == "\n") {
- position++;
- result += nativeLineEnd;
- }
-
- collectionResult = collectSequenceNotCRLF(s, position);
-
- token = collectionResult.collected;
- position = collectionResult.newPosition;
-
- result += token;
- }
-
- return result;
- }
-
- function collectSequenceNotCRLF(
- s,
- position,
- ) {
- const start = position;
- for (
- let c = s.charAt(position);
- position < s.length && !(c == "\r" || c == "\n");
- c = s.charAt(++position)
- );
- return { collected: s.slice(start, position), newPosition: position };
- }
-
- function toUint8Arrays(
- blobParts,
- doNormalizeLineEndingsToNative,
- ) {
- const ret = [];
- const enc = new TextEncoder();
- for (const element of blobParts) {
- if (typeof element === "string") {
- let str = element;
- if (doNormalizeLineEndingsToNative) {
- str = convertLineEndingsToNative(element);
- }
- ret.push(enc.encode(str));
- // eslint-disable-next-line @typescript-eslint/no-use-before-define
- } else if (element instanceof Blob) {
- ret.push(element[bytesSymbol]);
- } else if (element instanceof Uint8Array) {
- ret.push(element);
- } else if (element instanceof Uint16Array) {
- const uint8 = new Uint8Array(element.buffer);
- ret.push(uint8);
- } else if (element instanceof Uint32Array) {
- const uint8 = new Uint8Array(element.buffer);
- ret.push(uint8);
- } else if (ArrayBuffer.isView(element)) {
- // Convert view to Uint8Array.
- const uint8 = new Uint8Array(element.buffer);
- ret.push(uint8);
- } else if (element instanceof ArrayBuffer) {
- // Create a new Uint8Array view for the given ArrayBuffer.
- const uint8 = new Uint8Array(element);
- ret.push(uint8);
- } else {
- ret.push(enc.encode(String(element)));
- }
- }
- return ret;
- }
-
- function processBlobParts(
- blobParts,
- options,
- ) {
- const normalizeLineEndingsToNative = options.ending === "native";
- // ArrayBuffer.transfer is not yet implemented in V8, so we just have to
- // pre compute size of the array buffer and do some sort of static allocation
- // instead of dynamic allocation.
- const uint8Arrays = toUint8Arrays(blobParts, normalizeLineEndingsToNative);
- const byteLength = uint8Arrays
- .map((u8) => u8.byteLength)
- .reduce((a, b) => a + b, 0);
- const ab = new ArrayBuffer(byteLength);
- const bytes = new Uint8Array(ab);
- let courser = 0;
- for (const u8 of uint8Arrays) {
- bytes.set(u8, courser);
- courser += u8.byteLength;
- }
-
- return bytes;
- }
-
- function getStream(blobBytes) {
- // TODO: Align to spec https://fetch.spec.whatwg.org/#concept-construct-readablestream
- return new ReadableStream({
- type: "bytes",
- start: (controller) => {
- controller.enqueue(blobBytes);
- controller.close();
- },
- });
- }
-
- async function readBytes(
- reader,
- ) {
- const chunks = [];
- while (true) {
- const { done, value } = await reader.read();
- if (!done && value instanceof Uint8Array) {
- chunks.push(value);
- } else if (done) {
- const size = chunks.reduce((p, i) => p + i.byteLength, 0);
- const bytes = new Uint8Array(size);
- let offs = 0;
- for (const chunk of chunks) {
- bytes.set(chunk, offs);
- offs += chunk.byteLength;
- }
- return bytes.buffer;
- } else {
- throw new TypeError("Invalid reader result.");
- }
- }
- }
-
- // A WeakMap holding blob to byte array mapping.
- // Ensures it does not impact garbage collection.
- const blobBytesWeakMap = new WeakMap();
-
- class Blob {
- constructor(blobParts, options) {
- if (arguments.length === 0) {
- this[bytesSymbol] = new Uint8Array();
- return;
- }
-
- const { ending = "transparent", type = "" } = options ?? {};
- // Normalize options.type.
- let normalizedType = type;
- if (!containsOnlyASCII(type)) {
- normalizedType = "";
- } else {
- if (type.length) {
- for (let i = 0; i < type.length; ++i) {
- const char = type[i];
- if (char < "\u0020" || char > "\u007E") {
- normalizedType = "";
- break;
- }
- }
- normalizedType = type.toLowerCase();
- }
- }
- const bytes = processBlobParts(blobParts, { ending, type });
- // Set Blob object's properties.
- this[bytesSymbol] = bytes;
- this.size = bytes.byteLength;
- this.type = normalizedType;
- }
-
- slice(start, end, contentType) {
- return new Blob([this[bytesSymbol].slice(start, end)], {
- type: contentType || this.type,
- });
- }
-
- stream() {
- return getStream(this[bytesSymbol]);
- }
-
- async text() {
- const reader = getStream(this[bytesSymbol]).getReader();
- const decoder = new TextDecoder();
- return decoder.decode(await readBytes(reader));
- }
-
- arrayBuffer() {
- return readBytes(getStream(this[bytesSymbol]).getReader());
- }
- }
-
- window.__bootstrap.blob = {
- Blob,
- bytesSymbol,
- containsOnlyASCII,
- blobBytesWeakMap,
- };
-})(this);
diff --git a/cli/rt/20_headers.js b/cli/rt/20_headers.js
deleted file mode 100644
index ccde77e8d..000000000
--- a/cli/rt/20_headers.js
+++ /dev/null
@@ -1,256 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-((window) => {
- const { DomIterableMixin } = window.__bootstrap.domIterable;
- const { requiredArguments } = window.__bootstrap.webUtil;
-
- // From node-fetch
- // Copyright (c) 2016 David Frank. MIT License.
- const invalidTokenRegex = /[^\^_`a-zA-Z\-0-9!#$%&'*+.|~]/;
- const invalidHeaderCharRegex = /[^\t\x20-\x7e\x80-\xff]/;
-
- function isHeaders(value) {
- // eslint-disable-next-line @typescript-eslint/no-use-before-define
- return value instanceof Headers;
- }
-
- const headersData = Symbol("headers data");
-
- // TODO: headerGuard? Investigate if it is needed
- // node-fetch did not implement this but it is in the spec
- function normalizeParams(name, value) {
- name = String(name).toLowerCase();
- value = String(value).trim();
- return [name, value];
- }
-
- // The following name/value validations are copied from
- // https://github.com/bitinn/node-fetch/blob/master/src/headers.js
- // Copyright (c) 2016 David Frank. MIT License.
- function validateName(name) {
- if (invalidTokenRegex.test(name) || name === "") {
- throw new TypeError(`${name} is not a legal HTTP header name`);
- }
- }
-
- function validateValue(value) {
- if (invalidHeaderCharRegex.test(value)) {
- throw new TypeError(`${value} is not a legal HTTP header value`);
- }
- }
-
- /** Appends a key and value to the header list.
- *
- * The spec indicates that when a key already exists, the append adds the new
- * value onto the end of the existing value. The behaviour of this though
- * varies when the key is `set-cookie`. In this case, if the key of the cookie
- * already exists, the value is replaced, but if the key of the cookie does not
- * exist, and additional `set-cookie` header is added.
- *
- * The browser specification of `Headers` is written for clients, and not
- * servers, and Deno is a server, meaning that it needs to follow the patterns
- * expected for servers, of which a `set-cookie` header is expected for each
- * unique cookie key, but duplicate cookie keys should not exist. */
- function dataAppend(
- data,
- key,
- value,
- ) {
- for (let i = 0; i < data.length; i++) {
- const [dataKey] = data[i];
- if (key === "set-cookie" && dataKey === "set-cookie") {
- const [, dataValue] = data[i];
- const [dataCookieKey] = dataValue.split("=");
- const [cookieKey] = value.split("=");
- if (dataCookieKey === cookieKey) {
- data[i][1] = value;
- return;
- }
- } else {
- if (dataKey === key) {
- data[i][1] += `, ${value}`;
- return;
- }
- }
- }
- data.push([key, value]);
- }
-
- /** Gets a value of a key in the headers list.
- *
- * This varies slightly from spec behaviour in that when the key is `set-cookie`
- * the value returned will look like a concatenated value, when in fact, if the
- * headers were iterated over, each individual `set-cookie` value is a unique
- * entry in the headers list. */
- function dataGet(
- data,
- key,
- ) {
- const setCookieValues = [];
- for (const [dataKey, value] of data) {
- if (dataKey === key) {
- if (key === "set-cookie") {
- setCookieValues.push(value);
- } else {
- return value;
- }
- }
- }
- if (setCookieValues.length) {
- return setCookieValues.join(", ");
- }
- return undefined;
- }
-
- /** Sets a value of a key in the headers list.
- *
- * The spec indicates that the value should be replaced if the key already
- * exists. The behaviour here varies, where if the key is `set-cookie` the key
- * of the cookie is inspected, and if the key of the cookie already exists,
- * then the value is replaced. If the key of the cookie is not found, then
- * the value of the `set-cookie` is added to the list of headers.
- *
- * The browser specification of `Headers` is written for clients, and not
- * servers, and Deno is a server, meaning that it needs to follow the patterns
- * expected for servers, of which a `set-cookie` header is expected for each
- * unique cookie key, but duplicate cookie keys should not exist. */
- function dataSet(
- data,
- key,
- value,
- ) {
- for (let i = 0; i < data.length; i++) {
- const [dataKey] = data[i];
- if (dataKey === key) {
- // there could be multiple set-cookie headers, but all others are unique
- if (key === "set-cookie") {
- const [, dataValue] = data[i];
- const [dataCookieKey] = dataValue.split("=");
- const [cookieKey] = value.split("=");
- if (cookieKey === dataCookieKey) {
- data[i][1] = value;
- return;
- }
- } else {
- data[i][1] = value;
- return;
- }
- }
- }
- data.push([key, value]);
- }
-
- function dataDelete(data, key) {
- let i = 0;
- while (i < data.length) {
- const [dataKey] = data[i];
- if (dataKey === key) {
- data.splice(i, 1);
- } else {
- i++;
- }
- }
- }
-
- function dataHas(data, key) {
- for (const [dataKey] of data) {
- if (dataKey === key) {
- return true;
- }
- }
- return false;
- }
-
- // ref: https://fetch.spec.whatwg.org/#dom-headers
- class HeadersBase {
- constructor(init) {
- if (init === null) {
- throw new TypeError(
- "Failed to construct 'Headers'; The provided value was not valid",
- );
- } else if (isHeaders(init)) {
- this[headersData] = [...init];
- } else {
- this[headersData] = [];
- if (Array.isArray(init)) {
- for (const tuple of init) {
- // If header does not contain exactly two items,
- // then throw a TypeError.
- // ref: https://fetch.spec.whatwg.org/#concept-headers-fill
- requiredArguments(
- "Headers.constructor tuple array argument",
- tuple.length,
- 2,
- );
-
- this.append(tuple[0], tuple[1]);
- }
- } else if (init) {
- for (const [rawName, rawValue] of Object.entries(init)) {
- this.append(rawName, rawValue);
- }
- }
- }
- }
-
- [Symbol.for("Deno.customInspect")]() {
- let length = this[headersData].length;
- let output = "";
- for (const [key, value] of this[headersData]) {
- const prefix = length === this[headersData].length ? " " : "";
- const postfix = length === 1 ? " " : ", ";
- output = output + `${prefix}${key}: ${value}${postfix}`;
- length--;
- }
- return `Headers {${output}}`;
- }
-
- // ref: https://fetch.spec.whatwg.org/#concept-headers-append
- append(name, value) {
- requiredArguments("Headers.append", arguments.length, 2);
- const [newname, newvalue] = normalizeParams(name, value);
- validateName(newname);
- validateValue(newvalue);
- dataAppend(this[headersData], newname, newvalue);
- }
-
- delete(name) {
- requiredArguments("Headers.delete", arguments.length, 1);
- const [newname] = normalizeParams(name);
- validateName(newname);
- dataDelete(this[headersData], newname);
- }
-
- get(name) {
- requiredArguments("Headers.get", arguments.length, 1);
- const [newname] = normalizeParams(name);
- validateName(newname);
- return dataGet(this[headersData], newname) ?? null;
- }
-
- has(name) {
- requiredArguments("Headers.has", arguments.length, 1);
- const [newname] = normalizeParams(name);
- validateName(newname);
- return dataHas(this[headersData], newname);
- }
-
- set(name, value) {
- requiredArguments("Headers.set", arguments.length, 2);
- const [newname, newvalue] = normalizeParams(name, value);
- validateName(newname);
- validateValue(newvalue);
- dataSet(this[headersData], newname, newvalue);
- }
-
- get [Symbol.toStringTag]() {
- return "Headers";
- }
- }
-
- class Headers extends DomIterableMixin(HeadersBase, headersData) {}
-
- window.__bootstrap.headers = {
- Headers,
- };
-})(this);
diff --git a/cli/rt/20_streams_queuing_strategy.js b/cli/rt/20_streams_queuing_strategy.js
deleted file mode 100644
index af32c7d2e..000000000
--- a/cli/rt/20_streams_queuing_strategy.js
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-((window) => {
- const customInspect = Symbol.for("Deno.customInspect");
-
- class CountQueuingStrategy {
- constructor({ highWaterMark }) {
- this.highWaterMark = highWaterMark;
- }
-
- size() {
- return 1;
- }
-
- [customInspect]() {
- return `${this.constructor.name} { highWaterMark: ${
- String(this.highWaterMark)
- }, size: f }`;
- }
- }
-
- Object.defineProperty(CountQueuingStrategy.prototype, "size", {
- enumerable: true,
- });
-
- class ByteLengthQueuingStrategy {
- constructor({ highWaterMark }) {
- this.highWaterMark = highWaterMark;
- }
-
- size(chunk) {
- return chunk.byteLength;
- }
-
- [customInspect]() {
- return `${this.constructor.name} { highWaterMark: ${
- String(this.highWaterMark)
- }, size: f }`;
- }
- }
-
- Object.defineProperty(ByteLengthQueuingStrategy.prototype, "size", {
- enumerable: true,
- });
-
- window.__bootstrap.queuingStrategy = {
- CountQueuingStrategy,
- ByteLengthQueuingStrategy,
- };
-})(this);
diff --git a/cli/rt/21_dom_file.js b/cli/rt/21_dom_file.js
deleted file mode 100644
index 9d2f7fb6b..000000000
--- a/cli/rt/21_dom_file.js
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-((window) => {
- const blob = window.__bootstrap.blob;
-
- class DomFile extends blob.Blob {
- constructor(
- fileBits,
- fileName,
- options,
- ) {
- const { lastModified = Date.now(), ...blobPropertyBag } = options ?? {};
- super(fileBits, blobPropertyBag);
-
- // 4.1.2.1 Replace any "/" character (U+002F SOLIDUS)
- // with a ":" (U + 003A COLON)
- this.name = String(fileName).replace(/\u002F/g, "\u003A");
- // 4.1.3.3 If lastModified is not provided, set lastModified to the current
- // date and time represented in number of milliseconds since the Unix Epoch.
- this.lastModified = lastModified;
- }
- }
-
- window.__bootstrap.domFile = {
- DomFile,
- };
-})(this);
diff --git a/cli/rt/22_form_data.js b/cli/rt/22_form_data.js
deleted file mode 100644
index cc656d387..000000000
--- a/cli/rt/22_form_data.js
+++ /dev/null
@@ -1,116 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-((window) => {
- const blob = window.__bootstrap.blob;
- const domFile = window.__bootstrap.domFile;
- const { DomIterableMixin } = window.__bootstrap.domIterable;
- const { requiredArguments } = window.__bootstrap.webUtil;
-
- const dataSymbol = Symbol("data");
-
- function parseFormDataValue(value, filename) {
- if (value instanceof domFile.DomFile) {
- return new domFile.DomFile([value], filename || value.name, {
- type: value.type,
- lastModified: value.lastModified,
- });
- } else if (value instanceof blob.Blob) {
- return new domFile.DomFile([value], filename || "blob", {
- type: value.type,
- });
- } else {
- return String(value);
- }
- }
-
- class FormDataBase {
- [dataSymbol] = [];
-
- append(name, value, filename) {
- requiredArguments("FormData.append", arguments.length, 2);
- name = String(name);
- this[dataSymbol].push([name, parseFormDataValue(value, filename)]);
- }
-
- delete(name) {
- requiredArguments("FormData.delete", arguments.length, 1);
- name = String(name);
- let i = 0;
- while (i < this[dataSymbol].length) {
- if (this[dataSymbol][i][0] === name) {
- this[dataSymbol].splice(i, 1);
- } else {
- i++;
- }
- }
- }
-
- getAll(name) {
- requiredArguments("FormData.getAll", arguments.length, 1);
- name = String(name);
- const values = [];
- for (const entry of this[dataSymbol]) {
- if (entry[0] === name) {
- values.push(entry[1]);
- }
- }
-
- return values;
- }
-
- get(name) {
- requiredArguments("FormData.get", arguments.length, 1);
- name = String(name);
- for (const entry of this[dataSymbol]) {
- if (entry[0] === name) {
- return entry[1];
- }
- }
-
- return null;
- }
-
- has(name) {
- requiredArguments("FormData.has", arguments.length, 1);
- name = String(name);
- return this[dataSymbol].some((entry) => entry[0] === name);
- }
-
- set(name, value, filename) {
- requiredArguments("FormData.set", arguments.length, 2);
- name = String(name);
-
- // If there are any entries in the context object’s entry list whose name
- // is name, replace the first such entry with entry and remove the others
- let found = false;
- let i = 0;
- while (i < this[dataSymbol].length) {
- if (this[dataSymbol][i][0] === name) {
- if (!found) {
- this[dataSymbol][i][1] = parseFormDataValue(value, filename);
- found = true;
- } else {
- this[dataSymbol].splice(i, 1);
- continue;
- }
- }
- i++;
- }
-
- // Otherwise, append entry to the context object’s entry list.
- if (!found) {
- this[dataSymbol].push([name, parseFormDataValue(value, filename)]);
- }
- }
-
- get [Symbol.toStringTag]() {
- return "FormData";
- }
- }
-
- class FormData extends DomIterableMixin(FormDataBase, dataSymbol) {}
-
- window.__bootstrap.formData = {
- FormData,
- };
-})(this);
diff --git a/cli/rt/23_multipart.js b/cli/rt/23_multipart.js
deleted file mode 100644
index 25c261b98..000000000
--- a/cli/rt/23_multipart.js
+++ /dev/null
@@ -1,199 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-((window) => {
- const { Buffer } = window.__bootstrap.buffer;
- const { bytesSymbol, Blob } = window.__bootstrap.blob;
- const { DomFile } = window.__bootstrap.domFile;
- const { getHeaderValueParams } = window.__bootstrap.webUtil;
-
- const decoder = new TextDecoder();
- const encoder = new TextEncoder();
- const CR = "\r".charCodeAt(0);
- const LF = "\n".charCodeAt(0);
-
- class MultipartBuilder {
- constructor(formData, boundary) {
- this.formData = formData;
- this.boundary = boundary ?? this.#createBoundary();
- this.writer = new Buffer();
- }
-
- getContentType() {
- return `multipart/form-data; boundary=${this.boundary}`;
- }
-
- getBody() {
- for (const [fieldName, fieldValue] of this.formData.entries()) {
- if (fieldValue instanceof DomFile) {
- this.#writeFile(fieldName, fieldValue);
- } else this.#writeField(fieldName, fieldValue);
- }
-
- this.writer.writeSync(encoder.encode(`\r\n--${this.boundary}--`));
-
- return this.writer.bytes();
- }
-
- #createBoundary = () => {
- return (
- "----------" +
- Array.from(Array(32))
- .map(() => Math.random().toString(36)[2] || 0)
- .join("")
- );
- };
-
- #writeHeaders = (headers) => {
- let buf = this.writer.empty() ? "" : "\r\n";
-
- buf += `--${this.boundary}\r\n`;
- for (const [key, value] of headers) {
- buf += `${key}: ${value}\r\n`;
- }
- buf += `\r\n`;
-
- this.writer.writeSync(encoder.encode(buf));
- };
-
- #writeFileHeaders = (
- field,
- filename,
- type,
- ) => {
- const headers = [
- [
- "Content-Disposition",
- `form-data; name="${field}"; filename="${filename}"`,
- ],
- ["Content-Type", type || "application/octet-stream"],
- ];
- return this.#writeHeaders(headers);
- };
-
- #writeFieldHeaders = (field) => {
- const headers = [["Content-Disposition", `form-data; name="${field}"`]];
- return this.#writeHeaders(headers);
- };
-
- #writeField = (field, value) => {
- this.#writeFieldHeaders(field);
- this.writer.writeSync(encoder.encode(value));
- };
-
- #writeFile = (field, value) => {
- this.#writeFileHeaders(field, value.name, value.type);
- this.writer.writeSync(value[bytesSymbol]);
- };
- }
-
- class MultipartParser {
- constructor(body, boundary) {
- if (!boundary) {
- throw new TypeError("multipart/form-data must provide a boundary");
- }
-
- this.boundary = `--${boundary}`;
- this.body = body;
- this.boundaryChars = encoder.encode(this.boundary);
- }
-
- #parseHeaders = (headersText) => {
- const headers = new Headers();
- const rawHeaders = headersText.split("\r\n");
- for (const rawHeader of rawHeaders) {
- const sepIndex = rawHeader.indexOf(":");
- if (sepIndex < 0) {
- continue; // Skip this header
- }
- const key = rawHeader.slice(0, sepIndex);
- const value = rawHeader.slice(sepIndex + 1);
- headers.set(key, value);
- }
-
- return {
- headers,
- disposition: getHeaderValueParams(
- headers.get("Content-Disposition") ?? "",
- ),
- };
- };
-
- parse() {
- const formData = new FormData();
- let headerText = "";
- let boundaryIndex = 0;
- let state = 0;
- let fileStart = 0;
-
- for (let i = 0; i < this.body.length; i++) {
- const byte = this.body[i];
- const prevByte = this.body[i - 1];
- const isNewLine = byte === LF && prevByte === CR;
-
- if (state === 1 || state === 2 || state == 3) {
- headerText += String.fromCharCode(byte);
- }
- if (state === 0 && isNewLine) {
- state = 1;
- } else if (state === 1 && isNewLine) {
- state = 2;
- const headersDone = this.body[i + 1] === CR &&
- this.body[i + 2] === LF;
-
- if (headersDone) {
- state = 3;
- }
- } else if (state === 2 && isNewLine) {
- state = 3;
- } else if (state === 3 && isNewLine) {
- state = 4;
- fileStart = i + 1;
- } else if (state === 4) {
- if (this.boundaryChars[boundaryIndex] !== byte) {
- boundaryIndex = 0;
- } else {
- boundaryIndex++;
- }
-
- if (boundaryIndex >= this.boundary.length) {
- const { headers, disposition } = this.#parseHeaders(headerText);
- const content = this.body.subarray(
- fileStart,
- i - boundaryIndex - 1,
- );
- // https://fetch.spec.whatwg.org/#ref-for-dom-body-formdata
- const filename = disposition.get("filename");
- const name = disposition.get("name");
-
- state = 5;
- // Reset
- boundaryIndex = 0;
- headerText = "";
-
- if (!name) {
- continue; // Skip, unknown name
- }
-
- if (filename) {
- const blob = new Blob([content], {
- type: headers.get("Content-Type") || "application/octet-stream",
- });
- formData.append(name, blob, filename);
- } else {
- formData.append(name, decoder.decode(content));
- }
- }
- } else if (state === 5 && isNewLine) {
- state = 1;
- }
- }
-
- return formData;
- }
- }
-
- window.__bootstrap.multipart = {
- MultipartBuilder,
- MultipartParser,
- };
-})(this);
diff --git a/cli/rt/24_body.js b/cli/rt/24_body.js
deleted file mode 100644
index f755e2bad..000000000
--- a/cli/rt/24_body.js
+++ /dev/null
@@ -1,220 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-((window) => {
- const { Blob } = window.__bootstrap.blob;
- const { ReadableStream, isReadableStreamDisturbed } =
- window.__bootstrap.streams;
- const { Buffer } = window.__bootstrap.buffer;
- const {
- getHeaderValueParams,
- hasHeaderValueOf,
- isTypedArray,
- } = window.__bootstrap.webUtil;
- const { MultipartParser } = window.__bootstrap.multipart;
-
- function validateBodyType(owner, bodySource) {
- if (isTypedArray(bodySource)) {
- return true;
- } else if (bodySource instanceof ArrayBuffer) {
- return true;
- } else if (typeof bodySource === "string") {
- return true;
- } else if (bodySource instanceof ReadableStream) {
- return true;
- } else if (bodySource instanceof FormData) {
- return true;
- } else if (bodySource instanceof URLSearchParams) {
- return true;
- } else if (!bodySource) {
- return true; // null body is fine
- }
- throw new Error(
- `Bad ${owner.constructor.name} body type: ${bodySource.constructor.name}`,
- );
- }
-
- async function bufferFromStream(
- stream,
- size,
- ) {
- const encoder = new TextEncoder();
- const buffer = new Buffer();
-
- if (size) {
- // grow to avoid unnecessary allocations & copies
- buffer.grow(size);
- }
-
- while (true) {
- const { done, value } = await stream.read();
-
- if (done) break;
-
- if (typeof value === "string") {
- buffer.writeSync(encoder.encode(value));
- } else if (value instanceof ArrayBuffer) {
- buffer.writeSync(new Uint8Array(value));
- } else if (value instanceof Uint8Array) {
- buffer.writeSync(value);
- } else if (!value) {
- // noop for undefined
- } else {
- throw new Error("unhandled type on stream read");
- }
- }
-
- return buffer.bytes().buffer;
- }
-
- function bodyToArrayBuffer(bodySource) {
- if (isTypedArray(bodySource)) {
- return bodySource.buffer;
- } else if (bodySource instanceof ArrayBuffer) {
- return bodySource;
- } else if (typeof bodySource === "string") {
- const enc = new TextEncoder();
- return enc.encode(bodySource).buffer;
- } else if (bodySource instanceof ReadableStream) {
- throw new Error(
- `Can't convert stream to ArrayBuffer (try bufferFromStream)`,
- );
- } else if (
- bodySource instanceof FormData ||
- bodySource instanceof URLSearchParams
- ) {
- const enc = new TextEncoder();
- return enc.encode(bodySource.toString()).buffer;
- } else if (!bodySource) {
- return new ArrayBuffer(0);
- }
- throw new Error(
- `Body type not implemented: ${bodySource.constructor.name}`,
- );
- }
-
- const BodyUsedError =
- "Failed to execute 'clone' on 'Body': body is already used";
-
- class Body {
- #contentType = "";
- #size = undefined;
-
- constructor(_bodySource, meta) {
- validateBodyType(this, _bodySource);
- this._bodySource = _bodySource;
- this.#contentType = meta.contentType;
- this.#size = meta.size;
- this._stream = null;
- }
-
- get body() {
- if (this._stream) {
- return this._stream;
- }
-
- if (!this._bodySource) {
- return null;
- } else if (this._bodySource instanceof ReadableStream) {
- this._stream = this._bodySource;
- } else {
- const buf = bodyToArrayBuffer(this._bodySource);
- if (!(buf instanceof ArrayBuffer)) {
- throw new Error(
- `Expected ArrayBuffer from body`,
- );
- }
-
- this._stream = new ReadableStream({
- start(controller) {
- controller.enqueue(buf);
- controller.close();
- },
- });
- }
-
- return this._stream;
- }
-
- get bodyUsed() {
- if (this.body && isReadableStreamDisturbed(this.body)) {
- return true;
- }
- return false;
- }
-
- async blob() {
- return new Blob([await this.arrayBuffer()], {
- type: this.#contentType,
- });
- }
-
- // ref: https://fetch.spec.whatwg.org/#body-mixin
- async formData() {
- const formData = new FormData();
- if (hasHeaderValueOf(this.#contentType, "multipart/form-data")) {
- const params = getHeaderValueParams(this.#contentType);
-
- // ref: https://tools.ietf.org/html/rfc2046#section-5.1
- const boundary = params.get("boundary");
- const body = new Uint8Array(await this.arrayBuffer());
- const multipartParser = new MultipartParser(body, boundary);
-
- return multipartParser.parse();
- } else if (
- hasHeaderValueOf(this.#contentType, "application/x-www-form-urlencoded")
- ) {
- // From https://github.com/github/fetch/blob/master/fetch.js
- // Copyright (c) 2014-2016 GitHub, Inc. MIT License
- const body = await this.text();
- try {
- body
- .trim()
- .split("&")
- .forEach((bytes) => {
- if (bytes) {
- const split = bytes.split("=");
- const name = split.shift().replace(/\+/g, " ");
- const value = split.join("=").replace(/\+/g, " ");
- formData.append(
- decodeURIComponent(name),
- decodeURIComponent(value),
- );
- }
- });
- } catch (e) {
- throw new TypeError("Invalid form urlencoded format");
- }
- return formData;
- } else {
- throw new TypeError("Invalid form data");
- }
- }
-
- async text() {
- if (typeof this._bodySource === "string") {
- return this._bodySource;
- }
-
- const ab = await this.arrayBuffer();
- const decoder = new TextDecoder("utf-8");
- return decoder.decode(ab);
- }
-
- async json() {
- const raw = await this.text();
- return JSON.parse(raw);
- }
-
- arrayBuffer() {
- if (this._bodySource instanceof ReadableStream) {
- return bufferFromStream(this._bodySource.getReader(), this.#size);
- }
- return bodyToArrayBuffer(this._bodySource);
- }
- }
-
- window.__bootstrap.body = {
- Body,
- BodyUsedError,
- };
-})(this);
diff --git a/cli/rt/25_request.js b/cli/rt/25_request.js
deleted file mode 100644
index 467a66fe9..000000000
--- a/cli/rt/25_request.js
+++ /dev/null
@@ -1,139 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-((window) => {
- const body = window.__bootstrap.body;
- const { ReadableStream } = window.__bootstrap.streams;
-
- function byteUpperCase(s) {
- return String(s).replace(/[a-z]/g, function byteUpperCaseReplace(c) {
- return c.toUpperCase();
- });
- }
-
- function normalizeMethod(m) {
- const u = byteUpperCase(m);
- if (
- u === "DELETE" ||
- u === "GET" ||
- u === "HEAD" ||
- u === "OPTIONS" ||
- u === "POST" ||
- u === "PUT"
- ) {
- return u;
- }
- return m;
- }
-
- class Request extends body.Body {
- constructor(input, init) {
- if (arguments.length < 1) {
- throw TypeError("Not enough arguments");
- }
-
- if (!init) {
- init = {};
- }
-
- let b;
-
- // prefer body from init
- if (init.body) {
- b = init.body;
- } else if (input instanceof Request && input._bodySource) {
- if (input.bodyUsed) {
- throw TypeError(body.BodyUsedError);
- }
- b = input._bodySource;
- } else if (typeof input === "object" && "body" in input && input.body) {
- if (input.bodyUsed) {
- throw TypeError(body.BodyUsedError);
- }
- b = input.body;
- } else {
- b = "";
- }
-
- let headers;
-
- // prefer headers from init
- if (init.headers) {
- headers = new Headers(init.headers);
- } else if (input instanceof Request) {
- headers = input.headers;
- } else {
- headers = new Headers();
- }
-
- const contentType = headers.get("content-type") || "";
- super(b, { contentType });
- this.headers = headers;
-
- // readonly attribute ByteString method;
- this.method = "GET";
-
- // readonly attribute USVString url;
- this.url = "";
-
- // readonly attribute RequestCredentials credentials;
- this.credentials = "omit";
-
- if (input instanceof Request) {
- if (input.bodyUsed) {
- throw TypeError(body.BodyUsedError);
- }
- this.method = input.method;
- this.url = input.url;
- this.headers = new Headers(input.headers);
- this.credentials = input.credentials;
- this._stream = input._stream;
- } else if (typeof input === "string") {
- this.url = input;
- }
-
- if (init && "method" in init) {
- this.method = normalizeMethod(init.method);
- }
-
- if (
- init &&
- "credentials" in init &&
- init.credentials &&
- ["omit", "same-origin", "include"].indexOf(init.credentials) !== -1
- ) {
- this.credentials = init.credentials;
- }
- }
-
- clone() {
- if (this.bodyUsed) {
- throw TypeError(body.BodyUsedError);
- }
-
- const iterators = this.headers.entries();
- const headersList = [];
- for (const header of iterators) {
- headersList.push(header);
- }
-
- let body2 = this._bodySource;
-
- if (this._bodySource instanceof ReadableStream) {
- const tees = this._bodySource.tee();
- this._stream = this._bodySource = tees[0];
- body2 = tees[1];
- }
-
- return new Request(this.url, {
- body: body2,
- method: this.method,
- headers: new Headers(headersList),
- credentials: this.credentials,
- });
- }
- }
-
- window.__bootstrap.request = {
- Request,
- };
-})(this);
diff --git a/cli/rt/26_fetch.js b/cli/rt/26_fetch.js
deleted file mode 100644
index b337fbe10..000000000
--- a/cli/rt/26_fetch.js
+++ /dev/null
@@ -1,391 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-((window) => {
- const core = window.Deno.core;
- const { notImplemented } = window.__bootstrap.util;
- const { getHeaderValueParams, isTypedArray } = window.__bootstrap.webUtil;
- const { Blob, bytesSymbol: blobBytesSymbol } = window.__bootstrap.blob;
- const Body = window.__bootstrap.body;
- const { ReadableStream } = window.__bootstrap.streams;
- const { MultipartBuilder } = window.__bootstrap.multipart;
- const { Headers } = window.__bootstrap.headers;
-
- function createHttpClient(options) {
- return new HttpClient(opCreateHttpClient(options));
- }
-
- function opCreateHttpClient(args) {
- return core.jsonOpSync("op_create_http_client", args);
- }
-
- class HttpClient {
- constructor(rid) {
- this.rid = rid;
- }
- close() {
- core.close(this.rid);
- }
- }
-
- function opFetch(args, body) {
- let zeroCopy;
- if (body != null) {
- zeroCopy = new Uint8Array(body.buffer, body.byteOffset, body.byteLength);
- }
-
- return core.jsonOpAsync("op_fetch", args, ...(zeroCopy ? [zeroCopy] : []));
- }
-
- const NULL_BODY_STATUS = [101, 204, 205, 304];
- const REDIRECT_STATUS = [301, 302, 303, 307, 308];
-
- const responseData = new WeakMap();
- class Response extends Body.Body {
- constructor(body = null, init) {
- init = init ?? {};
-
- if (typeof init !== "object") {
- throw new TypeError(`'init' is not an object`);
- }
-
- const extraInit = responseData.get(init) || {};
- let { type = "default", url = "" } = extraInit;
-
- let status = init.status === undefined ? 200 : Number(init.status || 0);
- let statusText = init.statusText ?? "";
- let headers = init.headers instanceof Headers
- ? init.headers
- : new Headers(init.headers);
-
- if (init.status !== undefined && (status < 200 || status > 599)) {
- throw new RangeError(
- `The status provided (${init.status}) is outside the range [200, 599]`,
- );
- }
-
- // null body status
- if (body && NULL_BODY_STATUS.includes(status)) {
- throw new TypeError("Response with null body status cannot have body");
- }
-
- if (!type) {
- type = "default";
- } else {
- if (type == "error") {
- // spec: https://fetch.spec.whatwg.org/#concept-network-error
- status = 0;
- statusText = "";
- headers = new Headers();
- body = null;
- /* spec for other Response types:
- https://fetch.spec.whatwg.org/#concept-filtered-response-basic
- Please note that type "basic" is not the same thing as "default".*/
- } else if (type == "basic") {
- for (const h of headers) {
- /* Forbidden Response-Header Names:
- https://fetch.spec.whatwg.org/#forbidden-response-header-name */
- if (["set-cookie", "set-cookie2"].includes(h[0].toLowerCase())) {
- headers.delete(h[0]);
- }
- }
- } else if (type == "cors") {
- /* CORS-safelisted Response-Header Names:
- https://fetch.spec.whatwg.org/#cors-safelisted-response-header-name */
- const allowedHeaders = [
- "Cache-Control",
- "Content-Language",
- "Content-Length",
- "Content-Type",
- "Expires",
- "Last-Modified",
- "Pragma",
- ].map((c) => c.toLowerCase());
- for (const h of headers) {
- /* Technically this is still not standards compliant because we are
- supposed to allow headers allowed in the
- 'Access-Control-Expose-Headers' header in the 'internal response'
- However, this implementation of response doesn't seem to have an
- easy way to access the internal response, so we ignore that
- header.
- TODO(serverhiccups): change how internal responses are handled
- so we can do this properly. */
- if (!allowedHeaders.includes(h[0].toLowerCase())) {
- headers.delete(h[0]);
- }
- }
- /* TODO(serverhiccups): Once I fix the 'internal response' thing,
- these actually need to treat the internal response differently */
- } else if (type == "opaque" || type == "opaqueredirect") {
- url = "";
- status = 0;
- statusText = "";
- headers = new Headers();
- body = null;
- }
- }
-
- const contentType = headers.get("content-type") || "";
- const size = Number(headers.get("content-length")) || undefined;
-
- super(body, { contentType, size });
-
- this.url = url;
- this.statusText = statusText;
- this.status = extraInit.status || status;
- this.headers = headers;
- this.redirected = extraInit.redirected || false;
- this.type = type;
- }
-
- get ok() {
- return 200 <= this.status && this.status < 300;
- }
-
- clone() {
- if (this.bodyUsed) {
- throw TypeError(Body.BodyUsedError);
- }
-
- const iterators = this.headers.entries();
- const headersList = [];
- for (const header of iterators) {
- headersList.push(header);
- }
-
- let resBody = this._bodySource;
-
- if (this._bodySource instanceof ReadableStream) {
- const tees = this._bodySource.tee();
- this._stream = this._bodySource = tees[0];
- resBody = tees[1];
- }
-
- return new Response(resBody, {
- status: this.status,
- statusText: this.statusText,
- headers: new Headers(headersList),
- });
- }
-
- static redirect(url, status) {
- if (![301, 302, 303, 307, 308].includes(status)) {
- throw new RangeError(
- "The redirection status must be one of 301, 302, 303, 307 and 308.",
- );
- }
- return new Response(null, {
- status,
- statusText: "",
- headers: [["Location", typeof url === "string" ? url : url.toString()]],
- });
- }
- }
-
- function sendFetchReq(url, method, headers, body, clientRid) {
- let headerArray = [];
- if (headers) {
- headerArray = Array.from(headers.entries());
- }
-
- const args = {
- method,
- url,
- headers: headerArray,
- clientRid,
- };
-
- return opFetch(args, body);
- }
-
- async function fetch(input, init) {
- let url;
- let method = null;
- let headers = null;
- let body;
- let clientRid = null;
- let redirected = false;
- let remRedirectCount = 20; // TODO: use a better way to handle
-
- if (typeof input === "string" || input instanceof URL) {
- url = typeof input === "string" ? input : input.href;
- if (init != null) {
- method = init.method || null;
- if (init.headers) {
- headers = init.headers instanceof Headers
- ? init.headers
- : new Headers(init.headers);
- } else {
- headers = null;
- }
-
- // ref: https://fetch.spec.whatwg.org/#body-mixin
- // Body should have been a mixin
- // but we are treating it as a separate class
- if (init.body) {
- if (!headers) {
- headers = new Headers();
- }
- let contentType = "";
- if (typeof init.body === "string") {
- body = new TextEncoder().encode(init.body);
- contentType = "text/plain;charset=UTF-8";
- } else if (isTypedArray(init.body)) {
- body = init.body;
- } else if (init.body instanceof ArrayBuffer) {
- body = new Uint8Array(init.body);
- } else if (init.body instanceof URLSearchParams) {
- body = new TextEncoder().encode(init.body.toString());
- contentType = "application/x-www-form-urlencoded;charset=UTF-8";
- } else if (init.body instanceof Blob) {
- body = init.body[blobBytesSymbol];
- contentType = init.body.type;
- } else if (init.body instanceof FormData) {
- let boundary;
- if (headers.has("content-type")) {
- const params = getHeaderValueParams("content-type");
- boundary = params.get("boundary");
- }
- const multipartBuilder = new MultipartBuilder(init.body, boundary);
- body = multipartBuilder.getBody();
- contentType = multipartBuilder.getContentType();
- } else {
- // TODO: ReadableStream
- notImplemented();
- }
- if (contentType && !headers.has("content-type")) {
- headers.set("content-type", contentType);
- }
- }
-
- if (init.client instanceof HttpClient) {
- clientRid = init.client.rid;
- }
- }
- } else {
- url = input.url;
- method = input.method;
- headers = input.headers;
-
- if (input._bodySource) {
- body = new DataView(await input.arrayBuffer());
- }
- }
-
- let responseBody;
- let responseInit = {};
- while (remRedirectCount) {
- const fetchResponse = await sendFetchReq(
- url,
- method,
- headers,
- body,
- clientRid,
- );
- const rid = fetchResponse.bodyRid;
-
- if (
- NULL_BODY_STATUS.includes(fetchResponse.status) ||
- REDIRECT_STATUS.includes(fetchResponse.status)
- ) {
- // We won't use body of received response, so close it now
- // otherwise it will be kept in resource table.
- core.close(fetchResponse.bodyRid);
- responseBody = null;
- } else {
- responseBody = new ReadableStream({
- type: "bytes",
- async pull(controller) {
- try {
- const result = await core.jsonOpAsync("op_fetch_read", { rid });
- if (!result || !result.chunk) {
- controller.close();
- core.close(rid);
- } else {
- // TODO(ry) This is terribly inefficient. Make this zero-copy.
- const chunk = new Uint8Array(result.chunk);
- controller.enqueue(chunk);
- }
- } catch (e) {
- controller.error(e);
- controller.close();
- core.close(rid);
- }
- },
- cancel() {
- // When reader.cancel() is called
- core.close(rid);
- },
- });
- }
-
- responseInit = {
- status: 200,
- statusText: fetchResponse.statusText,
- headers: fetchResponse.headers,
- };
-
- responseData.set(responseInit, {
- redirected,
- rid: fetchResponse.bodyRid,
- status: fetchResponse.status,
- url,
- });
-
- const response = new Response(responseBody, responseInit);
-
- if (REDIRECT_STATUS.includes(fetchResponse.status)) {
- // We're in a redirect status
- switch ((init && init.redirect) || "follow") {
- case "error":
- responseInit = {};
- responseData.set(responseInit, {
- type: "error",
- redirected: false,
- url: "",
- });
- return new Response(null, responseInit);
- case "manual":
- responseInit = {};
- responseData.set(responseInit, {
- type: "opaqueredirect",
- redirected: false,
- url: "",
- });
- return new Response(null, responseInit);
- case "follow":
- default:
- let redirectUrl = response.headers.get("Location");
- if (redirectUrl == null) {
- return response; // Unspecified
- }
- if (
- !redirectUrl.startsWith("http://") &&
- !redirectUrl.startsWith("https://")
- ) {
- redirectUrl = new URL(redirectUrl, url).href;
- }
- url = redirectUrl;
- redirected = true;
- remRedirectCount--;
- }
- } else {
- return response;
- }
- }
-
- responseData.set(responseInit, {
- type: "error",
- redirected: false,
- url: "",
- });
-
- return new Response(null, responseInit);
- }
-
- window.__bootstrap.fetch = {
- fetch,
- Response,
- HttpClient,
- createHttpClient,
- };
-})(this);
diff --git a/cli/rt/21_filereader.js b/cli/rt/28_filereader.js
index ea1ca3e5f..ea1ca3e5f 100644
--- a/cli/rt/21_filereader.js
+++ b/cli/rt/28_filereader.js
diff --git a/cli/rt/99_main.js b/cli/rt/99_main.js
index 02834dcf3..8091823bb 100644
--- a/cli/rt/99_main.js
+++ b/cli/rt/99_main.js
@@ -22,15 +22,10 @@ delete Object.prototype.__proto__;
const crypto = window.__bootstrap.crypto;
const url = window.__bootstrap.url;
const headers = window.__bootstrap.headers;
- const queuingStrategy = window.__bootstrap.queuingStrategy;
const streams = window.__bootstrap.streams;
- const blob = window.__bootstrap.blob;
- const domFile = window.__bootstrap.domFile;
const progressEvent = window.__bootstrap.progressEvent;
const fileReader = window.__bootstrap.fileReader;
- const formData = window.__bootstrap.formData;
const webSocket = window.__bootstrap.webSocket;
- const request = window.__bootstrap.request;
const fetch = window.__bootstrap.fetch;
const denoNs = window.__bootstrap.denoNs;
const denoNsUnstable = window.__bootstrap.denoNsUnstable;
@@ -198,22 +193,22 @@ delete Object.prototype.__proto__;
// https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope
const windowOrWorkerGlobalScope = {
- Blob: util.nonEnumerable(blob.Blob),
+ Blob: util.nonEnumerable(fetch.Blob),
ByteLengthQueuingStrategy: util.nonEnumerable(
- queuingStrategy.ByteLengthQueuingStrategy,
+ streams.ByteLengthQueuingStrategy,
),
CloseEvent: util.nonEnumerable(CloseEvent),
CountQueuingStrategy: util.nonEnumerable(
- queuingStrategy.CountQueuingStrategy,
+ streams.CountQueuingStrategy,
),
CustomEvent: util.nonEnumerable(CustomEvent),
DOMException: util.nonEnumerable(DOMException),
ErrorEvent: util.nonEnumerable(ErrorEvent),
Event: util.nonEnumerable(Event),
EventTarget: util.nonEnumerable(EventTarget),
- File: util.nonEnumerable(domFile.DomFile),
+ File: util.nonEnumerable(fetch.DomFile),
FileReader: util.nonEnumerable(fileReader.FileReader),
- FormData: util.nonEnumerable(formData.FormData),
+ FormData: util.nonEnumerable(fetch.FormData),
Headers: util.nonEnumerable(headers.Headers),
MessageEvent: util.nonEnumerable(MessageEvent),
Performance: util.nonEnumerable(performance.Performance),
@@ -222,7 +217,7 @@ delete Object.prototype.__proto__;
PerformanceMeasure: util.nonEnumerable(performance.PerformanceMeasure),
ProgressEvent: util.nonEnumerable(progressEvent.ProgressEvent),
ReadableStream: util.nonEnumerable(streams.ReadableStream),
- Request: util.nonEnumerable(request.Request),
+ Request: util.nonEnumerable(fetch.Request),
Response: util.nonEnumerable(fetch.Response),
TextDecoder: util.nonEnumerable(TextDecoder),
TextEncoder: util.nonEnumerable(TextEncoder),