Skip to content

Commit

Permalink
Merge pull request #36 from MattiasBuelens/accept-abort-signal-polyfill
Browse files Browse the repository at this point in the history
Accept polyfilled abort signals
  • Loading branch information
MattiasBuelens authored Oct 7, 2019
2 parents 5fd3834 + 7d11d98 commit 3eb6ee9
Show file tree
Hide file tree
Showing 7 changed files with 48 additions and 25 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
## Unreleased

* 👓 Align with [spec version `ae5e0cb`](https://github.com/whatwg/streams/tree/ae5e0cb41e9f72cdd97f3a6d47bc674c1f4049d1/) ([#33](https://github.com/MattiasBuelens/web-streams-polyfill/pull/33))
* 💅 Accept polyfilled `AbortSignal`s. ([#36](https://github.com/MattiasBuelens/web-streams-polyfill/pull/36))

## v2.0.4 (2019-08-01)

Expand Down
10 changes: 10 additions & 0 deletions etc/web-streams-polyfill.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@
```ts

// @public
export interface AbortSignal {
// (undocumented)
readonly aborted: boolean;
// (undocumented)
addEventListener(type: 'abort', listener: () => void): void;
// (undocumented)
removeEventListener(type: 'abort', listener: () => void): void;
}

// @public (undocumented)
export class ByteLengthQueuingStrategy implements QueuingStrategy<ArrayBufferView> {
constructor({ highWaterMark }: {
Expand Down
28 changes: 28 additions & 0 deletions src/lib/abort-signal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* A signal object that allows you to communicate with a request and abort it if required
* via its associated `AbortController` object.
*
* @remarks
* This interface is compatible with the `AbortSignal` interface defined in TypeScript's DOM types.
* It is redefined here, so it can be polyfilled without a DOM, for example with
* {@link https://www.npmjs.com/package/abortcontroller-polyfill | abortcontroller-polyfill} in a Node environment.
*/
export interface AbortSignal {
readonly aborted: boolean;

addEventListener(type: 'abort', listener: () => void): void;

removeEventListener(type: 'abort', listener: () => void): void;
}

export function isAbortSignal(value: unknown): value is AbortSignal {
if (typeof value !== 'object' || value === null) {
return false;
}
try {
return typeof (value as AbortSignal).aborted === 'boolean';
} catch {
// AbortSignal.prototype.aborted throws if its brand check fails
return false;
}
}
18 changes: 1 addition & 17 deletions src/lib/readable-stream.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
/// <reference lib="dom" />

import assert from '../stub/assert';
import {
createArrayFromList,
Expand Down Expand Up @@ -59,6 +57,7 @@ import {
UnderlyingSource
} from './readable-stream/underlying-source';
import { noop } from '../utils';
import { AbortSignal, isAbortSignal } from './abort-signal';

export type ReadableByteStream = ReadableStream<Uint8Array>;

Expand Down Expand Up @@ -439,21 +438,6 @@ export {

// Helper functions for the ReadableStream.

export function isAbortSignal(value: any): value is AbortSignal {
if (typeof value !== 'object' || value === null) {
return false;
}

// Use the brand check to distinguish a real AbortSignal from a fake one.
const aborted = Object.getOwnPropertyDescriptor(AbortSignal.prototype, 'aborted')!.get!;
try {
aborted.call(value);
return true;
} catch (e) {
return false;
}
}

function streamBrandCheckException(name: string): TypeError {
return new TypeError(`ReadableStream.prototype.${name} can only be used on a ReadableStream`);
}
9 changes: 2 additions & 7 deletions src/lib/readable-stream/pipe.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,4 @@
import {
isAbortSignal,
IsReadableStream,
IsReadableStreamLocked,
ReadableStream,
ReadableStreamCancel
} from '../readable-stream';
import { IsReadableStream, IsReadableStreamLocked, ReadableStream, ReadableStreamCancel } from '../readable-stream';
import { AcquireReadableStreamDefaultReader, ReadableStreamDefaultReaderRead } from './default-reader';
import { ReadableStreamReaderGenericRelease } from './generic-reader';
import {
Expand All @@ -29,6 +23,7 @@ import {
uponRejection
} from '../helpers';
import { noop } from '../../utils';
import { AbortSignal, isAbortSignal } from '../abort-signal';

export function ReadableStreamPipeTo<T>(source: ReadableStream<T>,
dest: WritableStream<T>,
Expand Down
5 changes: 4 additions & 1 deletion src/ponyfill.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { QueuingStrategy } from './lib/queuing-strategy';
import ByteLengthQueuingStrategy from './lib/byte-length-queuing-strategy';
import CountQueuingStrategy from './lib/count-queuing-strategy';
import { Transformer, TransformStream, TransformStreamDefaultControllerType } from './lib/transform-stream';
import { AbortSignal } from './lib/abort-signal';

export {
ReadableStream,
Expand All @@ -46,5 +47,7 @@ export {

TransformStream,
Transformer,
TransformStreamDefaultControllerType as TransformStreamDefaultController
TransformStreamDefaultControllerType as TransformStreamDefaultController,

AbortSignal
};
2 changes: 2 additions & 0 deletions test/types/readable-stream.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ const asyncIteratorReturnResult: Promise<IteratorResult<any>> = asyncIterator.re
}
})();

const abortSignal: polyfill.AbortSignal = new AbortController().signal;

// Compatibility with stream types from DOM
const domUnderlyingSource: UnderlyingSource<string> = underlyingSource;
const domUnderlyingByteSource: UnderlyingByteSource = underlyingByteSource;
Expand Down

0 comments on commit 3eb6ee9

Please sign in to comment.