@skybloxsystems/ticket-bot
Version:
1,244 lines (1,226 loc) • 176 kB
JavaScript
/**
* web-streams-polyfill v3.2.0
*/
/// <reference lib="es2015.symbol" />
const SymbolPolyfill = typeof Symbol === 'function' && typeof Symbol.iterator === 'symbol' ?
Symbol :
description => `Symbol(${description})`;
/// <reference lib="dom" />
function noop() {
return undefined;
}
function getGlobals() {
if (typeof self !== 'undefined') {
return self;
}
else if (typeof window !== 'undefined') {
return window;
}
else if (typeof global !== 'undefined') {
return global;
}
return undefined;
}
const globals = getGlobals();
function typeIsObject(x) {
return (typeof x === 'object' && x !== null) || typeof x === 'function';
}
const rethrowAssertionErrorRejection = noop;
const originalPromise = Promise;
const originalPromiseThen = Promise.prototype.then;
const originalPromiseResolve = Promise.resolve.bind(originalPromise);
const originalPromiseReject = Promise.reject.bind(originalPromise);
function newPromise(executor) {
return new originalPromise(executor);
}
function promiseResolvedWith(value) {
return originalPromiseResolve(value);
}
function promiseRejectedWith(reason) {
return originalPromiseReject(reason);
}
function PerformPromiseThen(promise, onFulfilled, onRejected) {
// There doesn't appear to be any way to correctly emulate the behaviour from JavaScript, so this is just an
// approximation.
return originalPromiseThen.call(promise, onFulfilled, onRejected);
}
function uponPromise(promise, onFulfilled, onRejected) {
PerformPromiseThen(PerformPromiseThen(promise, onFulfilled, onRejected), undefined, rethrowAssertionErrorRejection);
}
function uponFulfillment(promise, onFulfilled) {
uponPromise(promise, onFulfilled);
}
function uponRejection(promise, onRejected) {
uponPromise(promise, undefined, onRejected);
}
function transformPromiseWith(promise, fulfillmentHandler, rejectionHandler) {
return PerformPromiseThen(promise, fulfillmentHandler, rejectionHandler);
}
function setPromiseIsHandledToTrue(promise) {
PerformPromiseThen(promise, undefined, rethrowAssertionErrorRejection);
}
const queueMicrotask = (() => {
const globalQueueMicrotask = globals && globals.queueMicrotask;
if (typeof globalQueueMicrotask === 'function') {
return globalQueueMicrotask;
}
const resolvedPromise = promiseResolvedWith(undefined);
return (fn) => PerformPromiseThen(resolvedPromise, fn);
})();
function reflectCall(F, V, args) {
if (typeof F !== 'function') {
throw new TypeError('Argument is not a function');
}
return Function.prototype.apply.call(F, V, args);
}
function promiseCall(F, V, args) {
try {
return promiseResolvedWith(reflectCall(F, V, args));
}
catch (value) {
return promiseRejectedWith(value);
}
}
// Original from Chromium
// https://chromium.googlesource.com/chromium/src/+/0aee4434a4dba42a42abaea9bfbc0cd196a63bc1/third_party/blink/renderer/core/streams/SimpleQueue.js
const QUEUE_MAX_ARRAY_SIZE = 16384;
/**
* Simple queue structure.
*
* Avoids scalability issues with using a packed array directly by using
* multiple arrays in a linked list and keeping the array size bounded.
*/
class SimpleQueue {
constructor() {
this._cursor = 0;
this._size = 0;
// _front and _back are always defined.
this._front = {
_elements: [],
_next: undefined
};
this._back = this._front;
// The cursor is used to avoid calling Array.shift().
// It contains the index of the front element of the array inside the
// front-most node. It is always in the range [0, QUEUE_MAX_ARRAY_SIZE).
this._cursor = 0;
// When there is only one node, size === elements.length - cursor.
this._size = 0;
}
get length() {
return this._size;
}
// For exception safety, this method is structured in order:
// 1. Read state
// 2. Calculate required state mutations
// 3. Perform state mutations
push(element) {
const oldBack = this._back;
let newBack = oldBack;
if (oldBack._elements.length === QUEUE_MAX_ARRAY_SIZE - 1) {
newBack = {
_elements: [],
_next: undefined
};
}
// push() is the mutation most likely to throw an exception, so it
// goes first.
oldBack._elements.push(element);
if (newBack !== oldBack) {
this._back = newBack;
oldBack._next = newBack;
}
++this._size;
}
// Like push(), shift() follows the read -> calculate -> mutate pattern for
// exception safety.
shift() { // must not be called on an empty queue
const oldFront = this._front;
let newFront = oldFront;
const oldCursor = this._cursor;
let newCursor = oldCursor + 1;
const elements = oldFront._elements;
const element = elements[oldCursor];
if (newCursor === QUEUE_MAX_ARRAY_SIZE) {
newFront = oldFront._next;
newCursor = 0;
}
// No mutations before this point.
--this._size;
this._cursor = newCursor;
if (oldFront !== newFront) {
this._front = newFront;
}
// Permit shifted element to be garbage collected.
elements[oldCursor] = undefined;
return element;
}
// The tricky thing about forEach() is that it can be called
// re-entrantly. The queue may be mutated inside the callback. It is easy to
// see that push() within the callback has no negative effects since the end
// of the queue is checked for on every iteration. If shift() is called
// repeatedly within the callback then the next iteration may return an
// element that has been removed. In this case the callback will be called
// with undefined values until we either "catch up" with elements that still
// exist or reach the back of the queue.
forEach(callback) {
let i = this._cursor;
let node = this._front;
let elements = node._elements;
while (i !== elements.length || node._next !== undefined) {
if (i === elements.length) {
node = node._next;
elements = node._elements;
i = 0;
if (elements.length === 0) {
break;
}
}
callback(elements[i]);
++i;
}
}
// Return the element that would be returned if shift() was called now,
// without modifying the queue.
peek() { // must not be called on an empty queue
const front = this._front;
const cursor = this._cursor;
return front._elements[cursor];
}
}
function ReadableStreamReaderGenericInitialize(reader, stream) {
reader._ownerReadableStream = stream;
stream._reader = reader;
if (stream._state === 'readable') {
defaultReaderClosedPromiseInitialize(reader);
}
else if (stream._state === 'closed') {
defaultReaderClosedPromiseInitializeAsResolved(reader);
}
else {
defaultReaderClosedPromiseInitializeAsRejected(reader, stream._storedError);
}
}
// A client of ReadableStreamDefaultReader and ReadableStreamBYOBReader may use these functions directly to bypass state
// check.
function ReadableStreamReaderGenericCancel(reader, reason) {
const stream = reader._ownerReadableStream;
return ReadableStreamCancel(stream, reason);
}
function ReadableStreamReaderGenericRelease(reader) {
if (reader._ownerReadableStream._state === 'readable') {
defaultReaderClosedPromiseReject(reader, new TypeError(`Reader was released and can no longer be used to monitor the stream's closedness`));
}
else {
defaultReaderClosedPromiseResetToRejected(reader, new TypeError(`Reader was released and can no longer be used to monitor the stream's closedness`));
}
reader._ownerReadableStream._reader = undefined;
reader._ownerReadableStream = undefined;
}
// Helper functions for the readers.
function readerLockException(name) {
return new TypeError('Cannot ' + name + ' a stream using a released reader');
}
// Helper functions for the ReadableStreamDefaultReader.
function defaultReaderClosedPromiseInitialize(reader) {
reader._closedPromise = newPromise((resolve, reject) => {
reader._closedPromise_resolve = resolve;
reader._closedPromise_reject = reject;
});
}
function defaultReaderClosedPromiseInitializeAsRejected(reader, reason) {
defaultReaderClosedPromiseInitialize(reader);
defaultReaderClosedPromiseReject(reader, reason);
}
function defaultReaderClosedPromiseInitializeAsResolved(reader) {
defaultReaderClosedPromiseInitialize(reader);
defaultReaderClosedPromiseResolve(reader);
}
function defaultReaderClosedPromiseReject(reader, reason) {
if (reader._closedPromise_reject === undefined) {
return;
}
setPromiseIsHandledToTrue(reader._closedPromise);
reader._closedPromise_reject(reason);
reader._closedPromise_resolve = undefined;
reader._closedPromise_reject = undefined;
}
function defaultReaderClosedPromiseResetToRejected(reader, reason) {
defaultReaderClosedPromiseInitializeAsRejected(reader, reason);
}
function defaultReaderClosedPromiseResolve(reader) {
if (reader._closedPromise_resolve === undefined) {
return;
}
reader._closedPromise_resolve(undefined);
reader._closedPromise_resolve = undefined;
reader._closedPromise_reject = undefined;
}
const AbortSteps = SymbolPolyfill('[[AbortSteps]]');
const ErrorSteps = SymbolPolyfill('[[ErrorSteps]]');
const CancelSteps = SymbolPolyfill('[[CancelSteps]]');
const PullSteps = SymbolPolyfill('[[PullSteps]]');
/// <reference lib="es2015.core" />
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isFinite#Polyfill
const NumberIsFinite = Number.isFinite || function (x) {
return typeof x === 'number' && isFinite(x);
};
/// <reference lib="es2015.core" />
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/trunc#Polyfill
const MathTrunc = Math.trunc || function (v) {
return v < 0 ? Math.ceil(v) : Math.floor(v);
};
// https://heycam.github.io/webidl/#idl-dictionaries
function isDictionary(x) {
return typeof x === 'object' || typeof x === 'function';
}
function assertDictionary(obj, context) {
if (obj !== undefined && !isDictionary(obj)) {
throw new TypeError(`${context} is not an object.`);
}
}
// https://heycam.github.io/webidl/#idl-callback-functions
function assertFunction(x, context) {
if (typeof x !== 'function') {
throw new TypeError(`${context} is not a function.`);
}
}
// https://heycam.github.io/webidl/#idl-object
function isObject(x) {
return (typeof x === 'object' && x !== null) || typeof x === 'function';
}
function assertObject(x, context) {
if (!isObject(x)) {
throw new TypeError(`${context} is not an object.`);
}
}
function assertRequiredArgument(x, position, context) {
if (x === undefined) {
throw new TypeError(`Parameter ${position} is required in '${context}'.`);
}
}
function assertRequiredField(x, field, context) {
if (x === undefined) {
throw new TypeError(`${field} is required in '${context}'.`);
}
}
// https://heycam.github.io/webidl/#idl-unrestricted-double
function convertUnrestrictedDouble(value) {
return Number(value);
}
function censorNegativeZero(x) {
return x === 0 ? 0 : x;
}
function integerPart(x) {
return censorNegativeZero(MathTrunc(x));
}
// https://heycam.github.io/webidl/#idl-unsigned-long-long
function convertUnsignedLongLongWithEnforceRange(value, context) {
const lowerBound = 0;
const upperBound = Number.MAX_SAFE_INTEGER;
let x = Number(value);
x = censorNegativeZero(x);
if (!NumberIsFinite(x)) {
throw new TypeError(`${context} is not a finite number`);
}
x = integerPart(x);
if (x < lowerBound || x > upperBound) {
throw new TypeError(`${context} is outside the accepted range of ${lowerBound} to ${upperBound}, inclusive`);
}
if (!NumberIsFinite(x) || x === 0) {
return 0;
}
// TODO Use BigInt if supported?
// let xBigInt = BigInt(integerPart(x));
// xBigInt = BigInt.asUintN(64, xBigInt);
// return Number(xBigInt);
return x;
}
function assertReadableStream(x, context) {
if (!IsReadableStream(x)) {
throw new TypeError(`${context} is not a ReadableStream.`);
}
}
// Abstract operations for the ReadableStream.
function AcquireReadableStreamDefaultReader(stream) {
return new ReadableStreamDefaultReader(stream);
}
// ReadableStream API exposed for controllers.
function ReadableStreamAddReadRequest(stream, readRequest) {
stream._reader._readRequests.push(readRequest);
}
function ReadableStreamFulfillReadRequest(stream, chunk, done) {
const reader = stream._reader;
const readRequest = reader._readRequests.shift();
if (done) {
readRequest._closeSteps();
}
else {
readRequest._chunkSteps(chunk);
}
}
function ReadableStreamGetNumReadRequests(stream) {
return stream._reader._readRequests.length;
}
function ReadableStreamHasDefaultReader(stream) {
const reader = stream._reader;
if (reader === undefined) {
return false;
}
if (!IsReadableStreamDefaultReader(reader)) {
return false;
}
return true;
}
/**
* A default reader vended by a {@link ReadableStream}.
*
* @public
*/
class ReadableStreamDefaultReader {
constructor(stream) {
assertRequiredArgument(stream, 1, 'ReadableStreamDefaultReader');
assertReadableStream(stream, 'First parameter');
if (IsReadableStreamLocked(stream)) {
throw new TypeError('This stream has already been locked for exclusive reading by another reader');
}
ReadableStreamReaderGenericInitialize(this, stream);
this._readRequests = new SimpleQueue();
}
/**
* Returns a promise that will be fulfilled when the stream becomes closed,
* or rejected if the stream ever errors or the reader's lock is released before the stream finishes closing.
*/
get closed() {
if (!IsReadableStreamDefaultReader(this)) {
return promiseRejectedWith(defaultReaderBrandCheckException('closed'));
}
return this._closedPromise;
}
/**
* If the reader is active, behaves the same as {@link ReadableStream.cancel | stream.cancel(reason)}.
*/
cancel(reason = undefined) {
if (!IsReadableStreamDefaultReader(this)) {
return promiseRejectedWith(defaultReaderBrandCheckException('cancel'));
}
if (this._ownerReadableStream === undefined) {
return promiseRejectedWith(readerLockException('cancel'));
}
return ReadableStreamReaderGenericCancel(this, reason);
}
/**
* Returns a promise that allows access to the next chunk from the stream's internal queue, if available.
*
* If reading a chunk causes the queue to become empty, more data will be pulled from the underlying source.
*/
read() {
if (!IsReadableStreamDefaultReader(this)) {
return promiseRejectedWith(defaultReaderBrandCheckException('read'));
}
if (this._ownerReadableStream === undefined) {
return promiseRejectedWith(readerLockException('read from'));
}
let resolvePromise;
let rejectPromise;
const promise = newPromise((resolve, reject) => {
resolvePromise = resolve;
rejectPromise = reject;
});
const readRequest = {
_chunkSteps: chunk => resolvePromise({ value: chunk, done: false }),
_closeSteps: () => resolvePromise({ value: undefined, done: true }),
_errorSteps: e => rejectPromise(e)
};
ReadableStreamDefaultReaderRead(this, readRequest);
return promise;
}
/**
* Releases the reader's lock on the corresponding stream. After the lock is released, the reader is no longer active.
* If the associated stream is errored when the lock is released, the reader will appear errored in the same way
* from now on; otherwise, the reader will appear closed.
*
* A reader's lock cannot be released while it still has a pending read request, i.e., if a promise returned by
* the reader's {@link ReadableStreamDefaultReader.read | read()} method has not yet been settled. Attempting to
* do so will throw a `TypeError` and leave the reader locked to the stream.
*/
releaseLock() {
if (!IsReadableStreamDefaultReader(this)) {
throw defaultReaderBrandCheckException('releaseLock');
}
if (this._ownerReadableStream === undefined) {
return;
}
if (this._readRequests.length > 0) {
throw new TypeError('Tried to release a reader lock when that reader has pending read() calls un-settled');
}
ReadableStreamReaderGenericRelease(this);
}
}
Object.defineProperties(ReadableStreamDefaultReader.prototype, {
cancel: { enumerable: true },
read: { enumerable: true },
releaseLock: { enumerable: true },
closed: { enumerable: true }
});
if (typeof SymbolPolyfill.toStringTag === 'symbol') {
Object.defineProperty(ReadableStreamDefaultReader.prototype, SymbolPolyfill.toStringTag, {
value: 'ReadableStreamDefaultReader',
configurable: true
});
}
// Abstract operations for the readers.
function IsReadableStreamDefaultReader(x) {
if (!typeIsObject(x)) {
return false;
}
if (!Object.prototype.hasOwnProperty.call(x, '_readRequests')) {
return false;
}
return x instanceof ReadableStreamDefaultReader;
}
function ReadableStreamDefaultReaderRead(reader, readRequest) {
const stream = reader._ownerReadableStream;
stream._disturbed = true;
if (stream._state === 'closed') {
readRequest._closeSteps();
}
else if (stream._state === 'errored') {
readRequest._errorSteps(stream._storedError);
}
else {
stream._readableStreamController[PullSteps](readRequest);
}
}
// Helper functions for the ReadableStreamDefaultReader.
function defaultReaderBrandCheckException(name) {
return new TypeError(`ReadableStreamDefaultReader.prototype.${name} can only be used on a ReadableStreamDefaultReader`);
}
/// <reference lib="es2018.asynciterable" />
let AsyncIteratorPrototype;
if (typeof SymbolPolyfill.asyncIterator === 'symbol') {
// We're running inside a ES2018+ environment, but we're compiling to an older syntax.
// We cannot access %AsyncIteratorPrototype% without non-ES2018 syntax, but we can re-create it.
AsyncIteratorPrototype = {
// 25.1.3.1 %AsyncIteratorPrototype% [ @@asyncIterator ] ( )
// https://tc39.github.io/ecma262/#sec-asynciteratorprototype-asynciterator
[SymbolPolyfill.asyncIterator]() {
return this;
}
};
Object.defineProperty(AsyncIteratorPrototype, SymbolPolyfill.asyncIterator, { enumerable: false });
}
/// <reference lib="es2018.asynciterable" />
class ReadableStreamAsyncIteratorImpl {
constructor(reader, preventCancel) {
this._ongoingPromise = undefined;
this._isFinished = false;
this._reader = reader;
this._preventCancel = preventCancel;
}
next() {
const nextSteps = () => this._nextSteps();
this._ongoingPromise = this._ongoingPromise ?
transformPromiseWith(this._ongoingPromise, nextSteps, nextSteps) :
nextSteps();
return this._ongoingPromise;
}
return(value) {
const returnSteps = () => this._returnSteps(value);
return this._ongoingPromise ?
transformPromiseWith(this._ongoingPromise, returnSteps, returnSteps) :
returnSteps();
}
_nextSteps() {
if (this._isFinished) {
return Promise.resolve({ value: undefined, done: true });
}
const reader = this._reader;
if (reader._ownerReadableStream === undefined) {
return promiseRejectedWith(readerLockException('iterate'));
}
let resolvePromise;
let rejectPromise;
const promise = newPromise((resolve, reject) => {
resolvePromise = resolve;
rejectPromise = reject;
});
const readRequest = {
_chunkSteps: chunk => {
this._ongoingPromise = undefined;
// This needs to be delayed by one microtask, otherwise we stop pulling too early which breaks a test.
// FIXME Is this a bug in the specification, or in the test?
queueMicrotask(() => resolvePromise({ value: chunk, done: false }));
},
_closeSteps: () => {
this._ongoingPromise = undefined;
this._isFinished = true;
ReadableStreamReaderGenericRelease(reader);
resolvePromise({ value: undefined, done: true });
},
_errorSteps: reason => {
this._ongoingPromise = undefined;
this._isFinished = true;
ReadableStreamReaderGenericRelease(reader);
rejectPromise(reason);
}
};
ReadableStreamDefaultReaderRead(reader, readRequest);
return promise;
}
_returnSteps(value) {
if (this._isFinished) {
return Promise.resolve({ value, done: true });
}
this._isFinished = true;
const reader = this._reader;
if (reader._ownerReadableStream === undefined) {
return promiseRejectedWith(readerLockException('finish iterating'));
}
if (!this._preventCancel) {
const result = ReadableStreamReaderGenericCancel(reader, value);
ReadableStreamReaderGenericRelease(reader);
return transformPromiseWith(result, () => ({ value, done: true }));
}
ReadableStreamReaderGenericRelease(reader);
return promiseResolvedWith({ value, done: true });
}
}
const ReadableStreamAsyncIteratorPrototype = {
next() {
if (!IsReadableStreamAsyncIterator(this)) {
return promiseRejectedWith(streamAsyncIteratorBrandCheckException('next'));
}
return this._asyncIteratorImpl.next();
},
return(value) {
if (!IsReadableStreamAsyncIterator(this)) {
return promiseRejectedWith(streamAsyncIteratorBrandCheckException('return'));
}
return this._asyncIteratorImpl.return(value);
}
};
if (AsyncIteratorPrototype !== undefined) {
Object.setPrototypeOf(ReadableStreamAsyncIteratorPrototype, AsyncIteratorPrototype);
}
// Abstract operations for the ReadableStream.
function AcquireReadableStreamAsyncIterator(stream, preventCancel) {
const reader = AcquireReadableStreamDefaultReader(stream);
const impl = new ReadableStreamAsyncIteratorImpl(reader, preventCancel);
const iterator = Object.create(ReadableStreamAsyncIteratorPrototype);
iterator._asyncIteratorImpl = impl;
return iterator;
}
function IsReadableStreamAsyncIterator(x) {
if (!typeIsObject(x)) {
return false;
}
if (!Object.prototype.hasOwnProperty.call(x, '_asyncIteratorImpl')) {
return false;
}
try {
// noinspection SuspiciousTypeOfGuard
return x._asyncIteratorImpl instanceof
ReadableStreamAsyncIteratorImpl;
}
catch (_a) {
return false;
}
}
// Helper functions for the ReadableStream.
function streamAsyncIteratorBrandCheckException(name) {
return new TypeError(`ReadableStreamAsyncIterator.${name} can only be used on a ReadableSteamAsyncIterator`);
}
/// <reference lib="es2015.core" />
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN#Polyfill
const NumberIsNaN = Number.isNaN || function (x) {
// eslint-disable-next-line no-self-compare
return x !== x;
};
function CreateArrayFromList(elements) {
// We use arrays to represent lists, so this is basically a no-op.
// Do a slice though just in case we happen to depend on the unique-ness.
return elements.slice();
}
function CopyDataBlockBytes(dest, destOffset, src, srcOffset, n) {
new Uint8Array(dest).set(new Uint8Array(src, srcOffset, n), destOffset);
}
// Not implemented correctly
function TransferArrayBuffer(O) {
return O;
}
// Not implemented correctly
// eslint-disable-next-line @typescript-eslint/no-unused-vars
function IsDetachedBuffer(O) {
return false;
}
function ArrayBufferSlice(buffer, begin, end) {
// ArrayBuffer.prototype.slice is not available on IE10
// https://www.caniuse.com/mdn-javascript_builtins_arraybuffer_slice
if (buffer.slice) {
return buffer.slice(begin, end);
}
const length = end - begin;
const slice = new ArrayBuffer(length);
CopyDataBlockBytes(slice, 0, buffer, begin, length);
return slice;
}
function IsNonNegativeNumber(v) {
if (typeof v !== 'number') {
return false;
}
if (NumberIsNaN(v)) {
return false;
}
if (v < 0) {
return false;
}
return true;
}
function CloneAsUint8Array(O) {
const buffer = ArrayBufferSlice(O.buffer, O.byteOffset, O.byteOffset + O.byteLength);
return new Uint8Array(buffer);
}
function DequeueValue(container) {
const pair = container._queue.shift();
container._queueTotalSize -= pair.size;
if (container._queueTotalSize < 0) {
container._queueTotalSize = 0;
}
return pair.value;
}
function EnqueueValueWithSize(container, value, size) {
if (!IsNonNegativeNumber(size) || size === Infinity) {
throw new RangeError('Size must be a finite, non-NaN, non-negative number.');
}
container._queue.push({ value, size });
container._queueTotalSize += size;
}
function PeekQueueValue(container) {
const pair = container._queue.peek();
return pair.value;
}
function ResetQueue(container) {
container._queue = new SimpleQueue();
container._queueTotalSize = 0;
}
/**
* A pull-into request in a {@link ReadableByteStreamController}.
*
* @public
*/
class ReadableStreamBYOBRequest {
constructor() {
throw new TypeError('Illegal constructor');
}
/**
* Returns the view for writing in to, or `null` if the BYOB request has already been responded to.
*/
get view() {
if (!IsReadableStreamBYOBRequest(this)) {
throw byobRequestBrandCheckException('view');
}
return this._view;
}
respond(bytesWritten) {
if (!IsReadableStreamBYOBRequest(this)) {
throw byobRequestBrandCheckException('respond');
}
assertRequiredArgument(bytesWritten, 1, 'respond');
bytesWritten = convertUnsignedLongLongWithEnforceRange(bytesWritten, 'First parameter');
if (this._associatedReadableByteStreamController === undefined) {
throw new TypeError('This BYOB request has been invalidated');
}
if (IsDetachedBuffer(this._view.buffer)) ;
ReadableByteStreamControllerRespond(this._associatedReadableByteStreamController, bytesWritten);
}
respondWithNewView(view) {
if (!IsReadableStreamBYOBRequest(this)) {
throw byobRequestBrandCheckException('respondWithNewView');
}
assertRequiredArgument(view, 1, 'respondWithNewView');
if (!ArrayBuffer.isView(view)) {
throw new TypeError('You can only respond with array buffer views');
}
if (this._associatedReadableByteStreamController === undefined) {
throw new TypeError('This BYOB request has been invalidated');
}
if (IsDetachedBuffer(view.buffer)) ;
ReadableByteStreamControllerRespondWithNewView(this._associatedReadableByteStreamController, view);
}
}
Object.defineProperties(ReadableStreamBYOBRequest.prototype, {
respond: { enumerable: true },
respondWithNewView: { enumerable: true },
view: { enumerable: true }
});
if (typeof SymbolPolyfill.toStringTag === 'symbol') {
Object.defineProperty(ReadableStreamBYOBRequest.prototype, SymbolPolyfill.toStringTag, {
value: 'ReadableStreamBYOBRequest',
configurable: true
});
}
/**
* Allows control of a {@link ReadableStream | readable byte stream}'s state and internal queue.
*
* @public
*/
class ReadableByteStreamController {
constructor() {
throw new TypeError('Illegal constructor');
}
/**
* Returns the current BYOB pull request, or `null` if there isn't one.
*/
get byobRequest() {
if (!IsReadableByteStreamController(this)) {
throw byteStreamControllerBrandCheckException('byobRequest');
}
return ReadableByteStreamControllerGetBYOBRequest(this);
}
/**
* Returns the desired size to fill the controlled stream's internal queue. It can be negative, if the queue is
* over-full. An underlying byte source ought to use this information to determine when and how to apply backpressure.
*/
get desiredSize() {
if (!IsReadableByteStreamController(this)) {
throw byteStreamControllerBrandCheckException('desiredSize');
}
return ReadableByteStreamControllerGetDesiredSize(this);
}
/**
* Closes the controlled readable stream. Consumers will still be able to read any previously-enqueued chunks from
* the stream, but once those are read, the stream will become closed.
*/
close() {
if (!IsReadableByteStreamController(this)) {
throw byteStreamControllerBrandCheckException('close');
}
if (this._closeRequested) {
throw new TypeError('The stream has already been closed; do not close it again!');
}
const state = this._controlledReadableByteStream._state;
if (state !== 'readable') {
throw new TypeError(`The stream (in ${state} state) is not in the readable state and cannot be closed`);
}
ReadableByteStreamControllerClose(this);
}
enqueue(chunk) {
if (!IsReadableByteStreamController(this)) {
throw byteStreamControllerBrandCheckException('enqueue');
}
assertRequiredArgument(chunk, 1, 'enqueue');
if (!ArrayBuffer.isView(chunk)) {
throw new TypeError('chunk must be an array buffer view');
}
if (chunk.byteLength === 0) {
throw new TypeError('chunk must have non-zero byteLength');
}
if (chunk.buffer.byteLength === 0) {
throw new TypeError(`chunk's buffer must have non-zero byteLength`);
}
if (this._closeRequested) {
throw new TypeError('stream is closed or draining');
}
const state = this._controlledReadableByteStream._state;
if (state !== 'readable') {
throw new TypeError(`The stream (in ${state} state) is not in the readable state and cannot be enqueued to`);
}
ReadableByteStreamControllerEnqueue(this, chunk);
}
/**
* Errors the controlled readable stream, making all future interactions with it fail with the given error `e`.
*/
error(e = undefined) {
if (!IsReadableByteStreamController(this)) {
throw byteStreamControllerBrandCheckException('error');
}
ReadableByteStreamControllerError(this, e);
}
/** @internal */
[CancelSteps](reason) {
ReadableByteStreamControllerClearPendingPullIntos(this);
ResetQueue(this);
const result = this._cancelAlgorithm(reason);
ReadableByteStreamControllerClearAlgorithms(this);
return result;
}
/** @internal */
[PullSteps](readRequest) {
const stream = this._controlledReadableByteStream;
if (this._queueTotalSize > 0) {
const entry = this._queue.shift();
this._queueTotalSize -= entry.byteLength;
ReadableByteStreamControllerHandleQueueDrain(this);
const view = new Uint8Array(entry.buffer, entry.byteOffset, entry.byteLength);
readRequest._chunkSteps(view);
return;
}
const autoAllocateChunkSize = this._autoAllocateChunkSize;
if (autoAllocateChunkSize !== undefined) {
let buffer;
try {
buffer = new ArrayBuffer(autoAllocateChunkSize);
}
catch (bufferE) {
readRequest._errorSteps(bufferE);
return;
}
const pullIntoDescriptor = {
buffer,
bufferByteLength: autoAllocateChunkSize,
byteOffset: 0,
byteLength: autoAllocateChunkSize,
bytesFilled: 0,
elementSize: 1,
viewConstructor: Uint8Array,
readerType: 'default'
};
this._pendingPullIntos.push(pullIntoDescriptor);
}
ReadableStreamAddReadRequest(stream, readRequest);
ReadableByteStreamControllerCallPullIfNeeded(this);
}
}
Object.defineProperties(ReadableByteStreamController.prototype, {
close: { enumerable: true },
enqueue: { enumerable: true },
error: { enumerable: true },
byobRequest: { enumerable: true },
desiredSize: { enumerable: true }
});
if (typeof SymbolPolyfill.toStringTag === 'symbol') {
Object.defineProperty(ReadableByteStreamController.prototype, SymbolPolyfill.toStringTag, {
value: 'ReadableByteStreamController',
configurable: true
});
}
// Abstract operations for the ReadableByteStreamController.
function IsReadableByteStreamController(x) {
if (!typeIsObject(x)) {
return false;
}
if (!Object.prototype.hasOwnProperty.call(x, '_controlledReadableByteStream')) {
return false;
}
return x instanceof ReadableByteStreamController;
}
function IsReadableStreamBYOBRequest(x) {
if (!typeIsObject(x)) {
return false;
}
if (!Object.prototype.hasOwnProperty.call(x, '_associatedReadableByteStreamController')) {
return false;
}
return x instanceof ReadableStreamBYOBRequest;
}
function ReadableByteStreamControllerCallPullIfNeeded(controller) {
const shouldPull = ReadableByteStreamControllerShouldCallPull(controller);
if (!shouldPull) {
return;
}
if (controller._pulling) {
controller._pullAgain = true;
return;
}
controller._pulling = true;
// TODO: Test controller argument
const pullPromise = controller._pullAlgorithm();
uponPromise(pullPromise, () => {
controller._pulling = false;
if (controller._pullAgain) {
controller._pullAgain = false;
ReadableByteStreamControllerCallPullIfNeeded(controller);
}
}, e => {
ReadableByteStreamControllerError(controller, e);
});
}
function ReadableByteStreamControllerClearPendingPullIntos(controller) {
ReadableByteStreamControllerInvalidateBYOBRequest(controller);
controller._pendingPullIntos = new SimpleQueue();
}
function ReadableByteStreamControllerCommitPullIntoDescriptor(stream, pullIntoDescriptor) {
let done = false;
if (stream._state === 'closed') {
done = true;
}
const filledView = ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor);
if (pullIntoDescriptor.readerType === 'default') {
ReadableStreamFulfillReadRequest(stream, filledView, done);
}
else {
ReadableStreamFulfillReadIntoRequest(stream, filledView, done);
}
}
function ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor) {
const bytesFilled = pullIntoDescriptor.bytesFilled;
const elementSize = pullIntoDescriptor.elementSize;
return new pullIntoDescriptor.viewConstructor(pullIntoDescriptor.buffer, pullIntoDescriptor.byteOffset, bytesFilled / elementSize);
}
function ReadableByteStreamControllerEnqueueChunkToQueue(controller, buffer, byteOffset, byteLength) {
controller._queue.push({ buffer, byteOffset, byteLength });
controller._queueTotalSize += byteLength;
}
function ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, pullIntoDescriptor) {
const elementSize = pullIntoDescriptor.elementSize;
const currentAlignedBytes = pullIntoDescriptor.bytesFilled - pullIntoDescriptor.bytesFilled % elementSize;
const maxBytesToCopy = Math.min(controller._queueTotalSize, pullIntoDescriptor.byteLength - pullIntoDescriptor.bytesFilled);
const maxBytesFilled = pullIntoDescriptor.bytesFilled + maxBytesToCopy;
const maxAlignedBytes = maxBytesFilled - maxBytesFilled % elementSize;
let totalBytesToCopyRemaining = maxBytesToCopy;
let ready = false;
if (maxAlignedBytes > currentAlignedBytes) {
totalBytesToCopyRemaining = maxAlignedBytes - pullIntoDescriptor.bytesFilled;
ready = true;
}
const queue = controller._queue;
while (totalBytesToCopyRemaining > 0) {
const headOfQueue = queue.peek();
const bytesToCopy = Math.min(totalBytesToCopyRemaining, headOfQueue.byteLength);
const destStart = pullIntoDescriptor.byteOffset + pullIntoDescriptor.bytesFilled;
CopyDataBlockBytes(pullIntoDescriptor.buffer, destStart, headOfQueue.buffer, headOfQueue.byteOffset, bytesToCopy);
if (headOfQueue.byteLength === bytesToCopy) {
queue.shift();
}
else {
headOfQueue.byteOffset += bytesToCopy;
headOfQueue.byteLength -= bytesToCopy;
}
controller._queueTotalSize -= bytesToCopy;
ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller, bytesToCopy, pullIntoDescriptor);
totalBytesToCopyRemaining -= bytesToCopy;
}
return ready;
}
function ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller, size, pullIntoDescriptor) {
pullIntoDescriptor.bytesFilled += size;
}
function ReadableByteStreamControllerHandleQueueDrain(controller) {
if (controller._queueTotalSize === 0 && controller._closeRequested) {
ReadableByteStreamControllerClearAlgorithms(controller);
ReadableStreamClose(controller._controlledReadableByteStream);
}
else {
ReadableByteStreamControllerCallPullIfNeeded(controller);
}
}
function ReadableByteStreamControllerInvalidateBYOBRequest(controller) {
if (controller._byobRequest === null) {
return;
}
controller._byobRequest._associatedReadableByteStreamController = undefined;
controller._byobRequest._view = null;
controller._byobRequest = null;
}
function ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller) {
while (controller._pendingPullIntos.length > 0) {
if (controller._queueTotalSize === 0) {
return;
}
const pullIntoDescriptor = controller._pendingPullIntos.peek();
if (ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, pullIntoDescriptor)) {
ReadableByteStreamControllerShiftPendingPullInto(controller);
ReadableByteStreamControllerCommitPullIntoDescriptor(controller._controlledReadableByteStream, pullIntoDescriptor);
}
}
}
function ReadableByteStreamControllerPullInto(controller, view, readIntoRequest) {
const stream = controller._controlledReadableByteStream;
let elementSize = 1;
if (view.constructor !== DataView) {
elementSize = view.constructor.BYTES_PER_ELEMENT;
}
const ctor = view.constructor;
// try {
const buffer = TransferArrayBuffer(view.buffer);
// } catch (e) {
// readIntoRequest._errorSteps(e);
// return;
// }
const pullIntoDescriptor = {
buffer,
bufferByteLength: buffer.byteLength,
byteOffset: view.byteOffset,
byteLength: view.byteLength,
bytesFilled: 0,
elementSize,
viewConstructor: ctor,
readerType: 'byob'
};
if (controller._pendingPullIntos.length > 0) {
controller._pendingPullIntos.push(pullIntoDescriptor);
// No ReadableByteStreamControllerCallPullIfNeeded() call since:
// - No change happens on desiredSize
// - The source has already been notified of that there's at least 1 pending read(view)
ReadableStreamAddReadIntoRequest(stream, readIntoRequest);
return;
}
if (stream._state === 'closed') {
const emptyView = new ctor(pullIntoDescriptor.buffer, pullIntoDescriptor.byteOffset, 0);
readIntoRequest._closeSteps(emptyView);
return;
}
if (controller._queueTotalSize > 0) {
if (ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, pullIntoDescriptor)) {
const filledView = ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor);
ReadableByteStreamControllerHandleQueueDrain(controller);
readIntoRequest._chunkSteps(filledView);
return;
}
if (controller._closeRequested) {
const e = new TypeError('Insufficient bytes to fill elements in the given buffer');
ReadableByteStreamControllerError(controller, e);
readIntoRequest._errorSteps(e);
return;
}
}
controller._pendingPullIntos.push(pullIntoDescriptor);
ReadableStreamAddReadIntoRequest(stream, readIntoRequest);
ReadableByteStreamControllerCallPullIfNeeded(controller);
}
function ReadableByteStreamControllerRespondInClosedState(controller, firstDescriptor) {
const stream = controller._controlledReadableByteStream;
if (ReadableStreamHasBYOBReader(stream)) {
while (ReadableStreamGetNumReadIntoRequests(stream) > 0) {
const pullIntoDescriptor = ReadableByteStreamControllerShiftPendingPullInto(controller);
ReadableByteStreamControllerCommitPullIntoDescriptor(stream, pullIntoDescriptor);
}
}
}
function ReadableByteStreamControllerRespondInReadableState(controller, bytesWritten, pullIntoDescriptor) {
ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller, bytesWritten, pullIntoDescriptor);
if (pullIntoDescriptor.bytesFilled < pullIntoDescriptor.elementSize) {
return;
}
ReadableByteStreamControllerShiftPendingPullInto(controller);
const remainderSize = pullIntoDescriptor.bytesFilled % pullIntoDescriptor.elementSize;
if (remainderSize > 0) {
const end = pullIntoDescriptor.byteOffset + pullIntoDescriptor.bytesFilled;
const remainder = ArrayBufferSlice(pullIntoDescriptor.buffer, end - remainderSize, end);
ReadableByteStreamControllerEnqueueChunkToQueue(controller, remainder, 0, remainder.byteLength);
}
pullIntoDescriptor.bytesFilled -= remainderSize;
ReadableByteStreamControllerCommitPullIntoDescriptor(controller._controlledReadableByteStream, pullIntoDescriptor);
ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller);
}
function ReadableByteStreamControllerRespondInternal(controller, bytesWritten) {
const firstDescriptor = controller._pendingPullIntos.peek();
ReadableByteStreamControllerInvalidateBYOBRequest(controller);
const state = controller._controlledReadableByteStream._state;
if (state === 'closed') {
ReadableByteStreamControllerRespondInClosedState(controller);
}
else {
ReadableByteStreamControllerRespondInReadableState(controller, bytesWritten, firstDescriptor);
}
ReadableByteStreamControllerCallPullIfNeeded(controller);
}
function ReadableByteStreamControllerShiftPendingPullInto(controller) {
const descriptor = controller._pendingPullIntos.shift();
return descriptor;
}
function ReadableByteStreamControllerShouldCallPull(controller) {
const stream = controller._controlledReadableByteStream;
if (stream._state !== 'readable') {
return false;
}
if (controller._closeRequested) {
return false;
}
if (!controller._started) {
return false;
}
if (ReadableStreamHasDefaultReader(stream) && ReadableStreamGetNumReadRequests(stream) > 0) {
return true;
}
if (ReadableStreamHasBYOBReader(stream) && ReadableStreamGetNumReadIntoRequests(stream) > 0) {
return true;
}
const desiredSize = ReadableByteStreamControllerGetDesiredSize(controller);
if (desiredSize > 0) {
return true;
}
return false;
}
function ReadableByteStreamControllerClearAlgorithms(controller) {
controller._pullAlgorithm = undefined;
controller._cancelAlgorithm = undefined;
}
// A client of ReadableByteStreamController may use these functions directly to bypass state check.
function ReadableByteStreamControllerClose(controller) {
const stream = controller._controlledReadableByteStream;
if (controller._closeRequested || stream._state !== 'readable') {
return;
}
if (controller._queueTotalSize > 0) {
controller._closeRequested = true;
return;
}
if (controller._pendingPullIntos.length > 0) {
const firstPendingPullInto = controller._pendingPullIntos.peek();
if (firstPendingPullInto.bytesFilled > 0) {
const e = new TypeError('Insufficient bytes to fill elements in the given buffer');
ReadableByteStreamControllerError(controller, e);
throw e;
}
}
ReadableByteStreamControllerClearAlgorithms(controller);
ReadableStreamClose(stream);
}
function ReadableByteStreamControllerEnqueue(controller, chunk) {
const stream = controller._controlledReadableByteStream;
if (controller._closeRequested || stream._state !== 'readable') {
return;
}
const buffer = chunk.buffer;
const byteOffset = chunk.byteOffset;
const byteLength = chunk.byteLength;
const transferredBuffer = TransferArrayBuffer(buffer);
if (controller._pendingPullIntos.length > 0) {
const firstPendingPullInto = controller._pendingPullIntos.peek();
if (IsDetachedBuffer(firstPendingPullInto.buffer)) ;
firstPendingPullInto.buffer = TransferArrayBuffer(firstPendingPullInto.buffer);
}
ReadableByteStreamControllerInvalidateBYOBRequest(controller);
if (ReadableStreamHasDefaultReader(stream)) {
if (ReadableStreamGetNumReadRequests(stream) === 0) {
ReadableByteStreamControllerEnqueueChunkToQueue(controller, transferredBuffer, byteOffset, byteLength);
}
else {
if (controller._pendingPullIntos.length > 0) {
ReadableByteStreamControllerShiftPendingPullInto(controller);
}
const transferredView = new Uint8Array(transferredBuffer, byteOffset, byteLength);
ReadableStreamFulfillReadRequest(stream, transferredView, false);
}
}
else if (ReadableStreamHasBYOBReader(stream)) {
// TODO: Ideally in this branch detaching should happen only if the buffer is not consumed fully.
ReadableByteStreamControllerEnqueueChunkToQueue(controller, transferredBuffer, byteOffset, byteLength);
ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller);
}
else {
ReadableByteStreamControllerEnqueueChunkToQueue(controller, transferredBuffer, byteOffset, byteLength);
}
ReadableByteStreamControllerCallPullIfNeeded(controller);
}
function ReadableByteStreamControllerError(controller, e) {
const stream = controller._controlledReadableByteStream;
if (stream._state !== 'readable') {
return;
}
ReadableByteStreamControllerClearPendingPullIntos(controller);
ResetQueue(controller);
ReadableByteStreamControllerClearAlgorithms(controller);
ReadableStreamError(stream, e);
}
function ReadableByteStreamControllerGetBYOBRequest(controller) {
if (controller._byobRequest === null && controller._pendingPullIntos.length > 0) {
const firstDescriptor = controller._pendingPullIntos.peek();
const view = new Uint8Array(firstDescriptor.buffer, firstDescriptor.byteOffset + firstDescriptor.bytesFilled, firstDescriptor.byteLength - firstDescriptor.bytesFilled);
const byobRequest = Object.create(ReadableStreamBYOBRequest.prototype);
SetUpReadableStreamBYOBRequest(byobRequest, controller, view);
controller._byobRequest = byobRequest;
}
return controller._byobRequest;