From b66ac3815ab5a32808a10388c0f086bbe4d9a318 Mon Sep 17 00:00:00 2001 From: Alessandro Vergani Date: Thu, 21 Sep 2017 12:30:58 +0200 Subject: [PATCH 1/5] Fixes issues with callback parameters and adds missing promisified --- types/node/index.d.ts | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/types/node/index.d.ts b/types/node/index.d.ts index 79f75145e8..8563a5959e 100644 --- a/types/node/index.d.ts +++ b/types/node/index.d.ts @@ -1986,7 +1986,10 @@ declare module "child_process" { encoding: BufferEncoding; } export interface ExecFileOptionsWithBufferEncoding extends ExecFileOptions { - encoding: string | null; // specify `null`. + encoding: 'buffer' | null; + } + export interface ExecFileOptionsWithOtherEncoding extends ExecFileOptions { + encoding: string; } export function execFile(file: string): ChildProcess; @@ -1996,19 +1999,20 @@ declare module "child_process" { // no `options` definitely means stdout/stderr are `string`. export function execFile(file: string, callback: (error: Error | null, stdout: string, stderr: string) => void): ChildProcess; + export function execFile(file: string, args: string[] | undefined | null, callback: (error: Error | null, stdout: string, stderr: string) => void): ChildProcess; // `options` with `"buffer"` or `null` for `encoding` means stdout/stderr are definitely `Buffer`. - export function execFile(file: string, options: { encoding: "buffer" | null } & ExecFileOptions, callback: (error: Error | null, stdout: string, stderr: string) => void): ChildProcess; - export function execFile(file: string, args: string[] | undefined | null, options: { encoding: "buffer" | null } & ExecFileOptions, callback: (error: Error | null, stdout: string, stderr: string) => void): ChildProcess; + export function execFile(file: string, options: ExecFileOptionsWithBufferEncoding, callback: (error: Error | null, stdout: Buffer, stderr: Buffer) => void): ChildProcess; + export function execFile(file: string, args: string[] | undefined | null, options: ExecFileOptionsWithBufferEncoding, callback: (error: Error | null, stdout: Buffer, stderr: Buffer) => void): ChildProcess; // `options` with well known `encoding` means stdout/stderr are definitely `string`. - export function execFile(file: string, options: { encoding: BufferEncoding } & ExecFileOptions, callback: (error: Error | null, stdout: Buffer, stderr: Buffer) => void): ChildProcess; - export function execFile(file: string, args: string[] | undefined | null, options: { encoding: BufferEncoding } & ExecFileOptions, callback: (error: Error | null, stdout: Buffer, stderr: Buffer) => void): ChildProcess; + export function execFile(file: string, options: ExecFileOptionsWithStringEncoding, callback: (error: Error | null, stdout: string, stderr: string) => void): ChildProcess; + export function execFile(file: string, args: string[] | undefined | null, options: ExecFileOptionsWithStringEncoding, callback: (error: Error | null, stdout: string, stderr: string) => void): ChildProcess; // `options` with an `encoding` whose type is `string` means stdout/stderr could either be `Buffer` or `string`. // There is no guarantee the `encoding` is unknown as `string` is a superset of `BufferEncoding`. - export function execFile(file: string, options: { encoding: string } & ExecFileOptions, callback: (error: Error | null, stdout: string | Buffer, stderr: string | Buffer) => void): ChildProcess; - export function execFile(file: string, args: string[] | undefined | null, options: { encoding: string } & ExecFileOptions, callback: (error: Error | null, stdout: string | Buffer, stderr: string | Buffer) => void): ChildProcess; + export function execFile(file: string, options: ExecFileOptionsWithOtherEncoding, callback: (error: Error | null, stdout: string | Buffer, stderr: string | Buffer) => void): ChildProcess; + export function execFile(file: string, args: string[] | undefined | null, options: ExecFileOptionsWithOtherEncoding, callback: (error: Error | null, stdout: string | Buffer, stderr: string | Buffer) => void): ChildProcess; // `options` without an `encoding` means stdout/stderr are definitely `string`. export function execFile(file: string, options: ExecFileOptions, callback: (error: Error | null, stdout: string, stderr: string) => void): ChildProcess; @@ -2021,12 +2025,13 @@ declare module "child_process" { // NOTE: This namespace provides design-time support for util.promisify. Exported members do not exist at runtime. export namespace execFile { export function __promisify__(file: string): Promise<{ stdout: string, stderr: string }>; - export function __promisify__(file: string, options: { encoding: "buffer" | null } & ExecFileOptions): Promise<{ stdout: string, stderr: string }>; - export function __promisify__(file: string, args: string[] | undefined | null, options: { encoding: "buffer" | null } & ExecFileOptions): Promise<{ stdout: string, stderr: string }>; - export function __promisify__(file: string, options: { encoding: BufferEncoding } & ExecFileOptions): Promise<{ stdout: Buffer, stderr: Buffer }>; - export function __promisify__(file: string, args: string[] | undefined | null, options: { encoding: BufferEncoding } & ExecFileOptions): Promise<{ stdout: Buffer, stderr: Buffer }>; - export function __promisify__(file: string, options: { encoding: string } & ExecFileOptions): Promise<{ stdout: string | Buffer, stderr: string | Buffer }>; - export function __promisify__(file: string, args: string[] | undefined | null, options: { encoding: string } & ExecFileOptions): Promise<{ stdout: string | Buffer, stderr: string | Buffer }>; + export function __promisify__(file: string, args: string[] | undefined | null): Promise<{ stdout: string, stderr: string }>; + export function __promisify__(file: string, options: ExecFileOptionsWithBufferEncoding): Promise<{ stdout: Buffer, stderr: Buffer }>; + export function __promisify__(file: string, args: string[] | undefined | null, options: ExecFileOptionsWithBufferEncoding): Promise<{ stdout: Buffer, stderr: Buffer }>; + export function __promisify__(file: string, options: ExecFileOptionsWithStringEncoding): Promise<{ stdout: string, stderr: string }>; + export function __promisify__(file: string, args: string[] | undefined | null, options: ExecFileOptionsWithStringEncoding): Promise<{ stdout: string, stderr: string }>; + export function __promisify__(file: string, options: ExecFileOptionsWithOtherEncoding): Promise<{ stdout: string | Buffer, stderr: string | Buffer }>; + export function __promisify__(file: string, args: string[] | undefined | null, options: ExecFileOptionsWithOtherEncoding): Promise<{ stdout: string | Buffer, stderr: string | Buffer }>; export function __promisify__(file: string, options: ExecFileOptions): Promise<{ stdout: string, stderr: string }>; export function __promisify__(file: string, args: string[] | undefined | null, options: ExecFileOptions): Promise<{ stdout: string, stderr: string }>; export function __promisify__(file: string, options: ({ encoding?: string | null } & ExecFileOptions) | undefined | null): Promise<{ stdout: string | Buffer, stderr: string | Buffer }>; From 3cc32b8e73320a5e9e4a17744236180f52c753d9 Mon Sep 17 00:00:00 2001 From: Alessandro Vergani Date: Thu, 21 Sep 2017 17:36:05 +0200 Subject: [PATCH 2/5] Fix whatwg-streams --- types/whatwg-streams/index.d.ts | 8 +- types/whatwg-streams/whatwg-streams-tests.ts | 298 ++++++++++--------- 2 files changed, 154 insertions(+), 152 deletions(-) diff --git a/types/whatwg-streams/index.d.ts b/types/whatwg-streams/index.d.ts index a268f9f571..02ad2c5152 100644 --- a/types/whatwg-streams/index.d.ts +++ b/types/whatwg-streams/index.d.ts @@ -3,13 +3,13 @@ // Definitions by: Kagami Sascha Rosylight // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -interface ReadableStreamSource { +export interface ReadableStreamSource { start?(controller: ReadableStreamDefaultController): void | Promise; pull?(controller: ReadableStreamDefaultController): void | Promise; cancel?(reason: string): void | Promise; } -interface ReadableByteStreamSource { +export interface ReadableByteStreamSource { start?(controller: ReadableByteStreamController): void | Promise; pull?(controller: ReadableByteStreamController): void | Promise; cancel?(reason: string): void | Promise; @@ -18,12 +18,12 @@ interface ReadableByteStreamSource { autoAllocateChunkSize?: number; } -interface QueuingStrategy { +export interface QueuingStrategy { size?(chunk: ArrayBufferView): number; highWaterMark?: number; } -interface PipeOptions { +export interface PipeOptions { preventClose?: boolean; preventAbort?: boolean; preventCancel?: boolean; diff --git a/types/whatwg-streams/whatwg-streams-tests.ts b/types/whatwg-streams/whatwg-streams-tests.ts index e26d755df6..528c2f1f01 100644 --- a/types/whatwg-streams/whatwg-streams-tests.ts +++ b/types/whatwg-streams/whatwg-streams-tests.ts @@ -1,27 +1,32 @@ /// +import { + ReadableStream, ReadableStreamSource, WritableStream, + ReadableStreamDefaultController, WritableStreamSink, WritableStreamDefaultController, ReadableByteStreamController +} from "whatwg-streams"; + // Examples taken from https://streams.spec.whatwg.org/#creating-examples // 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(); + } + }); +} + { - 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"); @@ -79,7 +84,7 @@ function makeUDPSocketStream(host: string, port: number) { return new ReadableStream({ type: "bytes", - start(controller) { + start(controller: ReadableByteStreamController) { readRepeatedly().catch(e => controller.error(e)); function readRepeatedly(): Promise { @@ -127,82 +132,78 @@ interface fs { } let fs: fs; -{ - const CHUNK_SIZE = 1024; +const CHUNK_SIZE = 1024; - function makeReadableFileStream(filename: string) { - let fd: number; - let position = 0; +function makeReadableFileStream(filename: string) { + let fd: number; + let position = 0; - return new ReadableStream({ - start() { - return fs.open(filename, "r").then(result => { - fd = result; - }); - }, + return new ReadableStream({ + start() { + return fs.open(filename, "r").then(result => { + fd = result; + }); + }, - pull(controller) { - const buffer = new ArrayBuffer(CHUNK_SIZE); + 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)); - } - }); - }, + 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); - } - }); - } + 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; +//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; +function makeReadableByteFileStream(filename: string) { + let fd: number; + let position = 0; - return new ReadableStream({ - type: "bytes", + return new ReadableStream({ + type: "bytes", - start() { - return fs.open(filename, "r").then(result => { - fd = result; - }); - }, + 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; + pull(controller: ReadableByteStreamController) { + // 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); - } - }); - }, + 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); - }, + cancel() { + return fs.close(fd); + }, - autoAllocateChunkSize: DEFAULT_CHUNK_SIZE - }); - } + autoAllocateChunkSize: DEFAULT_CHUNK_SIZE + }); } @@ -245,29 +246,29 @@ function makeWritableWebSocketStream(url: string, protocols: string | string[]) // 8.7. A writable stream with backpressure and success signals +//const fs = require("pr/fs"); // https://github.com/jden/pr + +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); + } + }); +} + { - //const fs = require("pr/fs"); // https://github.com/jden/pr - - 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); - } - }); - } - const fileStream = makeWritableFileStream("/example/path/on/fs.txt"); const writer = fileStream.getWriter(); @@ -282,65 +283,66 @@ function makeWritableWebSocketStream(url: string, protocols: string | string[]) // 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)) - }; +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)) + }; +} + +class WebSocketSource implements ReadableStreamSource { + private _ws: WebSocket; + + constructor(ws: WebSocket) { + this._ws = ws; } - class WebSocketSource implements ReadableStreamSource { - private _ws: WebSocket; + start(controller: ReadableStreamDefaultController) { + this._ws.onmessage = event => controller.enqueue(event.data); + this._ws.onclose = () => controller.close(); - constructor(ws: WebSocket) { - this._ws = ws; - } + this._ws.addEventListener("error", () => { + controller.error(new Error("The WebSocket errored!")); + }); + } - start(controller: ReadableStreamDefaultController) { - this._ws.onmessage = event => controller.enqueue(event.data); - this._ws.onclose = () => controller.close(); + cancel() { + this._ws.close(); + } +} - this._ws.addEventListener("error", () => { - controller.error(new Error("The WebSocket errored!")); - }); - } +class WebSocketSink implements WritableStreamSink { + private _ws: WebSocket; - cancel() { + 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(); - } - } - - 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(); From 3741861f7bdb33a72a1183c1e592829a5cff7595 Mon Sep 17 00:00:00 2001 From: Alessandro Vergani Date: Thu, 21 Sep 2017 17:36:35 +0200 Subject: [PATCH 3/5] Fix optics-agent --- types/optics-agent/index.d.ts | 20 +++++++++++--------- types/optics-agent/optics-agent-tests.ts | 11 ++++++++++- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/types/optics-agent/index.d.ts b/types/optics-agent/index.d.ts index 902e8e8379..89fc7de60f 100644 --- a/types/optics-agent/index.d.ts +++ b/types/optics-agent/index.d.ts @@ -83,12 +83,14 @@ export function middleware(): (req: Request, res: Response, next?: any) => void; export function instrumentHapiServer(server: Server): void; export function context(req: Request): any; -export default { - configureAgent, - instrumentSchema, - koaMiddleware, - middleware, - instrumentHapiServer, - context, - Agent, -}; +declare class OpticsAgent { + static configureAgent(options: Options): Agent; + static instrumentSchema(schema: GraphQLSchema): void; + static koaMiddleware(): (context: Context, next: () => Promise) => void; + static middleware(): (req: Request, res: Response, next?: any) => void; + static instrumentHapiServer(server: Server): void; + static context(req: Request): any; + static Agent: new (options: Options) => Agent; +} + +export default OpticsAgent; diff --git a/types/optics-agent/optics-agent-tests.ts b/types/optics-agent/optics-agent-tests.ts index 8ead943b5a..2135c810d4 100644 --- a/types/optics-agent/optics-agent-tests.ts +++ b/types/optics-agent/optics-agent-tests.ts @@ -1,10 +1,12 @@ import OpticsAgent, { configureAgent, instrumentSchema, + koaMiddleware, middleware, instrumentHapiServer, context, Options, + Agent, } from 'optics-agent'; import { GraphQLSchema } from 'graphql'; import * as express from 'express'; @@ -26,17 +28,24 @@ OpticsAgent.configureAgent(configOptions); const expressServer = express(); expressServer.use(OpticsAgent.middleware()); +expressServer.use(middleware()); const hapiServer = new hapi.Server(); OpticsAgent.instrumentHapiServer(hapiServer); +instrumentHapiServer(hapiServer); const koaServer = new KoaServer(); koaServer.use(OpticsAgent.koaMiddleware()); +koaServer.use(koaMiddleware()); declare const req: express.Request; OpticsAgent.context(req); +context(req); -const agent = new OpticsAgent.Agent({ apiKey: '1234' }); +let agent = new OpticsAgent.Agent({ apiKey: '1234' }); declare const schema: GraphQLSchema; agent.instrumentSchema(schema); + +agent = new Agent({ apiKey: '1234' }); +instrumentSchema(schema); From dde28abe0331b5cb9a7bafd7bf87edb28b8ee157 Mon Sep 17 00:00:00 2001 From: Alessandro Vergani Date: Thu, 21 Sep 2017 17:36:51 +0200 Subject: [PATCH 4/5] Add execFile tests --- types/node/node-tests.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/types/node/node-tests.ts b/types/node/node-tests.ts index 4786c6cfd9..bfd1eaa02e 100644 --- a/types/node/node-tests.ts +++ b/types/node/node-tests.ts @@ -1708,6 +1708,25 @@ namespace child_process_tests { childProcess.spawnSync("echo test"); } + { + childProcess.execFile("npm", () => {}); + childProcess.execFile("npm", ["-v"], () => {}); + childProcess.execFile("npm", ["-v"], { encoding: 'utf-8' }, (stdout, stderr) => { assert(stdout instanceof String); }); + childProcess.execFile("npm", ["-v"], { encoding: 'buffer' }, (stdout, stderr) => { assert(stdout instanceof Buffer); }); + childProcess.execFile("npm", { encoding: 'utf-8' }, (stdout, stderr) => { assert(stdout instanceof String); }); + childProcess.execFile("npm", { encoding: 'buffer' }, (stdout, stderr) => { assert(stdout instanceof Buffer); }); + } + + async function testPromisify() { + const execFile = util.promisify(childProcess.execFile); + let r: { stdout: string | Buffer, stderr: string | Buffer } = await execFile("npm"); + r = await execFile("npm", ["-v"]); + r = await execFile("npm", ["-v"], { encoding: 'utf-8' }); + r = await execFile("npm", ["-v"], { encoding: 'buffer' }); + r = await execFile("npm", { encoding: 'utf-8' }); + r = await execFile("npm", { encoding: 'buffer' }); + } + { let _cp: childProcess.ChildProcess; let _socket: net.Socket; From d0c94a2824344df0f8362731ab1d11a6d608cfe3 Mon Sep 17 00:00:00 2001 From: Alessandro Vergani Date: Fri, 22 Sep 2017 09:38:21 +0200 Subject: [PATCH 5/5] Refactoring of optics-agent --- types/optics-agent/index.d.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/types/optics-agent/index.d.ts b/types/optics-agent/index.d.ts index 89fc7de60f..83f7817bb9 100644 --- a/types/optics-agent/index.d.ts +++ b/types/optics-agent/index.d.ts @@ -83,14 +83,14 @@ export function middleware(): (req: Request, res: Response, next?: any) => void; export function instrumentHapiServer(server: Server): void; export function context(req: Request): any; -declare class OpticsAgent { - static configureAgent(options: Options): Agent; - static instrumentSchema(schema: GraphQLSchema): void; - static koaMiddleware(): (context: Context, next: () => Promise) => void; - static middleware(): (req: Request, res: Response, next?: any) => void; - static instrumentHapiServer(server: Server): void; - static context(req: Request): any; - static Agent: new (options: Options) => Agent; -} +declare const defaultExport: { + configureAgent: typeof configureAgent, + instrumentSchema: typeof instrumentSchema, + koaMiddleware: typeof koaMiddleware, + middleware: typeof middleware, + instrumentHapiServer: typeof instrumentHapiServer, + context: typeof context, + Agent: typeof Agent, +}; -export default OpticsAgent; +export default defaultExport;