diff --git a/whatwg-fetch/index.d.ts b/whatwg-fetch/index.d.ts
index f17d88a7df..67bde53016 100644
--- a/whatwg-fetch/index.d.ts
+++ b/whatwg-fetch/index.d.ts
@@ -6,9 +6,9 @@
///
interface Window {
- fetch(url: RequestInfo, init?: RequestInit): Promise;
+ fetch(input: RequestInfo, init?: RequestInit): Promise;
}
-declare var fetch: typeof window.fetch;
+declare let fetch: typeof window.fetch;
declare type HeadersInit = Headers | string[][] | { [key: string]: string };
declare class Headers {
@@ -16,7 +16,7 @@ declare class Headers {
append(name: string, value: string): void;
delete(name: string): void;
- get(name: string): string; // | null; (TS 2.0 strict null check)
+ get(name: string): string | null;
has(name: string): boolean;
set(name: string, value: string): void;
@@ -29,32 +29,35 @@ declare class Headers {
}
declare type BodyInit = Blob | ArrayBufferView | ArrayBuffer | FormData /* | URLSearchParams */ | string;
+declare type ResponseBodyInit = BodyInit | ReadableStream;
interface Body {
- bodyUsed: boolean;
+ readonly bodyUsed: boolean;
arrayBuffer(): Promise;
blob(): Promise;
formData(): Promise;
json(): Promise;
+ json(): Promise;
text(): Promise;
}
declare type RequestInfo = Request | string;
declare class Request {
- constructor(input: RequestInfo, init?: RequestInit);
-
- method: string;
- url: string;
- headers: Headers;
+ constructor(input: RequestInfo, init?: RequestInit);
- type: RequestType
- destination: RequestDestination;
- referrer: string;
- referrerPolicy: ReferrerPolicy;
- mode: RequestMode;
- credentials: RequestCredentials;
- cache: RequestCache;
- redirect: RequestRedirect;
- integrity: string;
+ readonly method: string;
+ readonly url: string;
+ readonly headers: Headers;
+
+ readonly type: RequestType
+ readonly destination: RequestDestination;
+ readonly referrer: string;
+ readonly referrerPolicy: ReferrerPolicy;
+ readonly mode: RequestMode;
+ readonly credentials: RequestCredentials;
+ readonly cache: RequestCache;
+ readonly redirect: RequestRedirect;
+ readonly integrity: string;
+ readonly keepalive: boolean;
clone(): Request;
}
@@ -70,7 +73,7 @@ interface RequestInit {
cache?: RequestCache;
redirect?: RequestRedirect;
integrity?: string;
- window?: any;
+ window?: null; // can only be set to null
}
type RequestType = "" | "audio" | "font" | "image" | "script" | "style" | "track" | "video";
@@ -79,27 +82,30 @@ type RequestMode = "navigate" | "same-origin" | "no-cors" | "cors";
type RequestCredentials = "omit" | "same-origin" | "include";
type RequestCache = "default" | "no-store" | "reload" | "no-cache" | "force-cache" | "only-if-cached";
type RequestRedirect = "follow" | "error" | "manual";
+
type ReferrerPolicy = "" | "no-referrer" | "no-referrer-when-downgrade" | "same-origin" | "origin" | "strict-origin" | "origin-when-cross-origin" | "strict-origin-when-cross-origin" | "unsafe-url";
declare class Response {
- constructor(body?: BodyInit, init?: ResponseInit);
+ constructor(body?: ResponseBodyInit, init?: ResponseInit);
static error(): Response;
static redirect(url: string, status?: number): Response;
- type: ResponseType;
- url: string;
- redirected: boolean;
- status: number;
- ok: boolean;
- statusText: string;
- headers: Headers;
- body: ReadableStream; // | null;
- trailer: Promise;
+ readonly type: ResponseType;
+
+ readonly url: string;
+ readonly redirected: boolean;
+ readonly status: number;
+ readonly ok: boolean;
+ readonly statusText: string;
+ readonly headers: Headers;
+ readonly body: ReadableStream | null;
+ readonly trailer: Promise;
clone(): Response;
}
interface Response extends Body {}
+
interface ResponseInit {
status?: number;
statusText?: string;
diff --git a/whatwg-fetch/tsconfig.json b/whatwg-fetch/tsconfig.json
index 2333d8dfc0..4e8f7e915e 100644
--- a/whatwg-fetch/tsconfig.json
+++ b/whatwg-fetch/tsconfig.json
@@ -3,7 +3,7 @@
"module": "commonjs",
"target": "es6",
"noImplicitAny": true,
- "strictNullChecks": false,
+ "strictNullChecks": true,
"baseUrl": "../",
"typeRoots": [
"../"
diff --git a/whatwg-fetch/whatwg-fetch-tests.ts b/whatwg-fetch/whatwg-fetch-tests.ts
index aa6b90b8c8..39a4cf9d2b 100644
--- a/whatwg-fetch/whatwg-fetch-tests.ts
+++ b/whatwg-fetch/whatwg-fetch-tests.ts
@@ -68,4 +68,43 @@ function handlePromise(promise: Promise) {
}).then((text) => {
console.log(text);
});
-}
\ No newline at end of file
+}
+
+function test_Body_json() {
+ interface FooBar {
+ foo: string;
+ bar: string;
+ }
+
+ fetch('http://test.com')
+ .then(response => response.json())
+ .then(fooBar => {
+ console.log(fooBar.foo);
+ console.log(fooBar.bar);
+ });
+
+ fetch('http://test.com')
+ .then(response => > response.json())
+ .then(fooBar => {
+ console.log(fooBar.foo);
+ console.log(fooBar.bar);
+ });
+
+ fetch('http://test.com')
+ .then(response => response.json() as Promise)
+ .then(fooBar => {
+ console.log(fooBar.foo);
+ console.log(fooBar.bar);
+ });
+
+ fetch('http://test.com')
+ .then(response => response.json())
+ .then(fooBar => {
+ // fooBar is of type any, not of type FooBar
+
+ // FIXME Was behaving properly with TypeScript 2.0.10, not anymore with 2.1.4
+ // See Wrong type with Promise chaining and 2.1.4 https://github.com/Microsoft/TypeScript/issues/12409
+ //console.log(fooBar.foo);
+ //console.log(fooBar.bar);
+ });
+}
diff --git a/whatwg-streams/index.d.ts b/whatwg-streams/index.d.ts
index 757189b190..4f1e26ee7c 100644
--- a/whatwg-streams/index.d.ts
+++ b/whatwg-streams/index.d.ts
@@ -15,11 +15,18 @@ interface ReadableByteStreamSource {
cancel?(reason: string): void | Promise;
type: "bytes";
+ autoAllocateChunkSize?: number;
}
interface QueuingStrategy {
- highWaterMark?: number;
size?(chunk: ArrayBufferView): number;
+ highWaterMark?: number;
+}
+
+interface PipeOptions {
+ preventClose?: boolean;
+ preventAbort?: boolean;
+ preventCancel?: boolean;
}
declare class ReadableStream {
@@ -31,8 +38,8 @@ declare class ReadableStream {
cancel(reason: string): Promise;
getReader(): ReadableStreamDefaultReader;
getReader({ mode }: { mode: "byob" }): ReadableStreamBYOBReader;
- pipeThrough({ writable, readable }: { writable: WritableStream, readable: T }): T;
- pipeTo(dest: WritableStream, { preventClose, preventAbort, preventCancel }: { preventClose?: boolean, preventAbort?: boolean, preventCancel?: boolean }): Promise;
+ pipeThrough({ writable, readable }: { writable: WritableStream, readable: T }, options?: PipeOptions): T;
+ pipeTo(dest: WritableStream, options?: PipeOptions): Promise;
tee(): [ReadableStream, ReadableStream];
}
@@ -49,7 +56,7 @@ declare class ReadableStreamDefaultReader {
declare class ReadableStreamBYOBReader {
constructor(stream: ReadableStream);
- closed: Promise;
+ closed: Promise;
cancel(reason: string): Promise;
read(view: ArrayBufferView): Promise>;
@@ -88,8 +95,8 @@ declare class ReadableStreamBYOBRequest {
interface WritableStreamSink {
start?(controller: WritableStreamDefaultController): void | Promise;
- write?(chunk: any): void | Promise;
- close?(): void | Promise;
+ write?(chunk: any, controller?: WritableStreamDefaultController): void | Promise;
+ close?(controller: WritableStreamDefaultController): void | Promise;
abort?(reason: string): void | Promise;
}
@@ -106,7 +113,7 @@ declare class WritableStreamDefaultWriter {
constructor(stream: WritableStream);
closed: Promise;
- desiredSize: number;
+ desiredSize: number | null;
ready: Promise;
abort(reason: string): Promise;
@@ -124,11 +131,11 @@ declare class WritableStreamDefaultController {
declare class ByteLengthQueuingStrategy {
constructor({ highWaterMark }: { highWaterMark: number });
- size(chunk: ArrayBufferView): number;
+ size(chunk: ArrayBufferView): number | undefined;
}
declare class CountQueuingStrategy {
constructor({ highWaterMark }: { highWaterMark: number });
- size(): number; // 1;
-}
\ No newline at end of file
+ size(): 1;
+}
diff --git a/whatwg-streams/tsconfig.json b/whatwg-streams/tsconfig.json
index 9c6a6ad155..318d69cb04 100644
--- a/whatwg-streams/tsconfig.json
+++ b/whatwg-streams/tsconfig.json
@@ -3,7 +3,7 @@
"module": "commonjs",
"target": "es6",
"noImplicitAny": true,
- "strictNullChecks": false,
+ "strictNullChecks": true,
"baseUrl": "../",
"typeRoots": [
"../"
diff --git a/whatwg-streams/whatwg-streams-tests.ts b/whatwg-streams/whatwg-streams-tests.ts
index ce5eb2b256..b1735b754f 100644
--- a/whatwg-streams/whatwg-streams-tests.ts
+++ b/whatwg-streams/whatwg-streams-tests.ts
@@ -1,20 +1,39 @@
-function makeReadableWebSocketStream(url: string, protocols: string[]) {
- const ws = new WebSocket(url, protocols);
- ws.binaryType = "arraybuffer";
+///
- return new ReadableStream({
- start(controller) {
- ws.onmessage = event => controller.enqueue(event.data);
- ws.onclose = () => controller.close();
- ws.onerror = () => controller.error(new Error("The WebSocket errored!"));
- },
+// Examples taken from https://streams.spec.whatwg.org/#creating-examples
- cancel() {
- ws.close();
- }
- });
+// 8.1. A readable stream with an underlying push source (no backpressure support)
+
+{
+ function makeReadableWebSocketStream(url: string, protocols: string | string[]) {
+ const ws = new WebSocket(url, protocols);
+ ws.binaryType = "arraybuffer";
+
+ return new ReadableStream({
+ start(controller) {
+ ws.onmessage = event => controller.enqueue(event.data);
+ ws.onclose = () => controller.close();
+ ws.onerror = () => controller.error(new Error("The WebSocket errored!"));
+ },
+
+ cancel() {
+ ws.close();
+ }
+ });
+ }
+
+ const writableStream = new WritableStream();
+
+ const webSocketStream = makeReadableWebSocketStream("wss://example.com:443/", "protocol");
+
+ webSocketStream.pipeTo(writableStream)
+ .then(() => console.log("All data successfully written!"))
+ .catch(e => console.error("Something went wrong!", e));
}
+
+// 8.2. A readable stream with an underlying push source and backpressure support
+
function makeReadableBackpressureSocketStream(host: string, port: number) {
const socket = createBackpressureSocket(host, port);
@@ -49,6 +68,9 @@ function makeReadableBackpressureSocketStream(host: string, port: number) {
function createBackpressureSocket(host: string, port: number): any { };
}
+
+// 8.3. A readable byte stream with an underlying push source (no backpressure support)
+
const DEFAULT_CHUNK_SIZE = 65536;
function makeUDPSocketStream(host: string, port: number) {
@@ -93,7 +115,100 @@ function makeUDPSocketStream(host: string, port: number) {
function createUDPSocket(host: string, port: number): any { };
}
-function makeWritableWebSocketStream(url: string, protocols: string[]) {
+
+// 8.4. A readable stream with an underlying pull source
+
+//const fs = require("pr/fs"); // https://github.com/jden/pr
+interface fs {
+ open(path: string | Buffer, flags: string | number): Promise;
+ read(fd: number, buffer: Buffer, offset: number, length: number, position: number): Promise;
+ write(fd: number, buffer: Buffer, offset: number, length: number): Promise;
+ close(fd: number): Promise;
+}
+let fs: fs;
+
+{
+ const CHUNK_SIZE = 1024;
+
+ function makeReadableFileStream(filename: string) {
+ let fd: number;
+ let position = 0;
+
+ return new ReadableStream({
+ start() {
+ return fs.open(filename, "r").then(result => {
+ fd = result;
+ });
+ },
+
+ pull(controller) {
+ const buffer = new ArrayBuffer(CHUNK_SIZE);
+
+ return fs.read(fd, buffer, 0, CHUNK_SIZE, position).then(bytesRead => {
+ if (bytesRead === 0) {
+ return fs.close(fd).then(() => controller.close());
+ } else {
+ position += bytesRead;
+ controller.enqueue(new Uint8Array(buffer, 0, bytesRead));
+ }
+ });
+ },
+
+ cancel() {
+ return fs.close(fd);
+ }
+ });
+ }
+}
+
+
+// 8.5. A readable byte stream with an underlying pull source
+
+{
+ //const fs = require("pr/fs"); // https://github.com/jden/pr
+ const DEFAULT_CHUNK_SIZE = 1024;
+
+ function makeReadableByteFileStream(filename: string) {
+ let fd: number;
+ let position = 0;
+
+ return new ReadableStream({
+ type: "bytes",
+
+ start() {
+ return fs.open(filename, "r").then(result => {
+ fd = result;
+ });
+ },
+
+ pull(controller) {
+ // Even when the consumer is using the default reader, the auto-allocation
+ // feature allocates a buffer and passes it to us via byobRequest.
+ const v = controller.byobRequest.view;
+
+ return fs.read(fd, v.buffer, v.byteOffset, v.byteLength, position).then(bytesRead => {
+ if (bytesRead === 0) {
+ return fs.close(fd).then(() => controller.close());
+ } else {
+ position += bytesRead;
+ controller.byobRequest.respond(bytesRead);
+ }
+ });
+ },
+
+ cancel() {
+ return fs.close(fd);
+ },
+
+ autoAllocateChunkSize: DEFAULT_CHUNK_SIZE
+ });
+ }
+}
+
+
+// 8.6. A writable stream with no backpressure or success signals
+
+function makeWritableWebSocketStream(url: string, protocols: string | string[]) {
const ws = new WebSocket(url, protocols);
return new WritableStream({
@@ -117,71 +232,123 @@ function makeWritableWebSocketStream(url: string, protocols: string[]) {
});
}
-function streamifyWebSocket(url: string, protocol: string) {
- const ws = new WebSocket(url, protocol);
- ws.binaryType = "arraybuffer";
+{
+ const readableStream = new ReadableStream();
- return {
- readable: new ReadableStream(new WebSocketSource(ws)),
- writable: new WritableStream(new WebSocketSink(ws))
- };
+ const webSocketStream = makeWritableWebSocketStream("wss://example.com:443/", "protocol");
+
+ readableStream.pipeTo(webSocketStream)
+ .then(() => console.log("All data successfully written!"))
+ .catch(e => console.error("Something went wrong!", e));
}
-class WebSocketSource implements ReadableStreamSource {
- private _ws: WebSocket
- constructor(ws: WebSocket) {
- this._ws = ws;
- }
+// 8.7. A writable stream with backpressure and success signals
- start(controller: ReadableStreamDefaultController) {
- this._ws.onmessage = event => controller.enqueue(event.data);
- this._ws.onclose = () => controller.close();
+{
+ //const fs = require("pr/fs"); // https://github.com/jden/pr
- this._ws.addEventListener("error", () => {
- controller.error(new Error("The WebSocket errored!"));
+ function makeWritableFileStream(filename: string) {
+ let fd: number;
+
+ return new WritableStream({
+ start() {
+ return fs.open(filename, "w").then(result => {
+ fd = result;
+ });
+ },
+
+ write(chunk) {
+ return fs.write(fd, chunk, 0, chunk.length);
+ },
+
+ close() {
+ return fs.close(fd);
+ }
});
}
- cancel() {
- this._ws.close();
- }
+ const fileStream = makeWritableFileStream("/example/path/on/fs.txt");
+ const writer = fileStream.getWriter();
+
+ writer.write("To stream, or not to stream\n");
+ writer.write("That is the question\n");
+
+ writer.close()
+ .then(() => console.log("chunks written and stream closed successfully!"))
+ .catch(e => console.error(e));
}
-class WebSocketSink implements WritableStreamSink {
- private _ws: WebSocket
- constructor(ws: WebSocket) {
- this._ws = ws;
+// 8.8. A { readable, writable } stream pair wrapping the same underlying resource
+
+{
+ function streamifyWebSocket(url: string, protocol: string) {
+ const ws = new WebSocket(url, protocol);
+ ws.binaryType = "arraybuffer";
+
+ return {
+ readable: new ReadableStream(new WebSocketSource(ws)),
+ writable: new WritableStream(new WebSocketSink(ws))
+ };
}
- start(controller: WritableStreamDefaultController) {
- this._ws.addEventListener("error", () => {
- controller.error(new Error("The WebSocket errored!"));
- });
+ class WebSocketSource implements ReadableStreamSource {
+ private _ws: WebSocket;
- return new Promise(resolve => this._ws.onopen = () => resolve());
- }
+ constructor(ws: WebSocket) {
+ this._ws = ws;
+ }
- write(chunk: any) {
- this._ws.send(chunk);
- }
+ start(controller: ReadableStreamDefaultController) {
+ this._ws.onmessage = event => controller.enqueue(event.data);
+ this._ws.onclose = () => controller.close();
- close() {
- return new Promise((resolve, reject) => {
- this._ws.onclose = () => resolve();
+ this._ws.addEventListener("error", () => {
+ controller.error(new Error("The WebSocket errored!"));
+ });
+ }
+
+ cancel() {
this._ws.close();
- });
+ }
}
+
+ class WebSocketSink implements WritableStreamSink {
+ private _ws: WebSocket;
+
+ constructor(ws: WebSocket) {
+ this._ws = ws;
+ }
+
+ start(controller: WritableStreamDefaultController) {
+ this._ws.addEventListener("error", () => {
+ controller.error(new Error("The WebSocket errored!"));
+ });
+
+ return new Promise(resolve => this._ws.onopen = () => resolve());
+ }
+
+ write(chunk: any) {
+ this._ws.send(chunk);
+ }
+
+ close() {
+ return new Promise((resolve, reject) => {
+ this._ws.onclose = () => resolve();
+ this._ws.close();
+ });
+ }
+ }
+
+ const streamyWS = streamifyWebSocket("wss://example.com:443/", "protocol");
+ const writer = streamyWS.writable.getWriter();
+ const reader = streamyWS.readable.getReader();
+
+ writer.write("Hello");
+ writer.write("web socket!");
+
+ reader.read().then(({ value, done }) => {
+ console.log("The web socket says: ", value);
+ });
}
-
-const streamyWS = streamifyWebSocket("wss://example.com:443/", "protocol");
-const writer = streamyWS.writable.getWriter();
-const reader = streamyWS.readable.getReader();
-
-writer.write("Hello");
-writer.write("web socket!");
-
-reader.read().then(({ value, done }) => {
- console.log("The web socket says: ", value);
-});
\ No newline at end of file