From e3e759ba0326d782809c203b4740bdcfdd37eaee Mon Sep 17 00:00:00 2001 From: legobeat <109787230+legobeat@users.noreply.github.com> Date: Wed, 15 May 2024 15:12:05 +0900 Subject: [PATCH] feat: Support overriding Duplex stream options as constructor options (#131) --- src/BasePostMessageStream.ts | 4 +++- .../WebWorkerParentPostMessageStream.ts | 7 ++++--- src/WebWorker/WebWorkerPostMessageStream.ts | 5 +++-- src/node-process/ProcessMessageStream.ts | 5 +++-- src/node-process/ProcessParentMessageStream.ts | 7 ++++--- src/node-thread/ThreadMessageStream.ts | 5 +++-- src/node-thread/ThreadParentMessageStream.ts | 7 ++++--- src/runtime/BrowserRuntimePostMessageStream.ts | 11 ++++++++--- src/window/WindowPostMessageStream.test.ts | 18 ++++++++++++++++++ src/window/WindowPostMessageStream.ts | 6 ++++-- 10 files changed, 54 insertions(+), 21 deletions(-) diff --git a/src/BasePostMessageStream.ts b/src/BasePostMessageStream.ts index 604cbfc..b94618e 100644 --- a/src/BasePostMessageStream.ts +++ b/src/BasePostMessageStream.ts @@ -1,4 +1,5 @@ import { Duplex } from 'readable-stream'; +import type { DuplexOptions } from 'readable-stream'; import { StreamData } from './utils'; const noop = () => undefined; @@ -24,9 +25,10 @@ export abstract class BasePostMessageStream extends Duplex { private _log: Log; - constructor() { + constructor(streamOptions?: DuplexOptions) { super({ objectMode: true, + ...streamOptions, }); // Initialization flags diff --git a/src/WebWorker/WebWorkerParentPostMessageStream.ts b/src/WebWorker/WebWorkerParentPostMessageStream.ts index 1b68d04..3d879d8 100644 --- a/src/WebWorker/WebWorkerParentPostMessageStream.ts +++ b/src/WebWorker/WebWorkerParentPostMessageStream.ts @@ -1,10 +1,11 @@ +import type { DuplexOptions } from 'readable-stream'; import { BasePostMessageStream, PostMessageEvent, } from '../BasePostMessageStream'; import { DEDICATED_WORKER_NAME, isValidStreamMessage } from '../utils'; -interface WorkerParentStreamArgs { +interface WorkerParentStreamArgs extends DuplexOptions { worker: Worker; } @@ -24,8 +25,8 @@ export class WebWorkerParentPostMessageStream extends BasePostMessageStream { * @param args.worker - The Web Worker to exchange messages with. The worker * must instantiate a `WebWorkerPostMessageStream`. */ - constructor({ worker }: WorkerParentStreamArgs) { - super(); + constructor({ worker, ...streamOptions }: WorkerParentStreamArgs) { + super(streamOptions); this._target = DEDICATED_WORKER_NAME; this._worker = worker; diff --git a/src/WebWorker/WebWorkerPostMessageStream.ts b/src/WebWorker/WebWorkerPostMessageStream.ts index e403405..9e355c9 100644 --- a/src/WebWorker/WebWorkerPostMessageStream.ts +++ b/src/WebWorker/WebWorkerPostMessageStream.ts @@ -1,5 +1,6 @@ // We ignore coverage for the entire file due to limits on our instrumentation, // but it is in fact covered by our tests. +import type { DuplexOptions } from 'readable-stream'; import { BasePostMessageStream, PostMessageEvent, @@ -17,7 +18,7 @@ import { export class WebWorkerPostMessageStream extends BasePostMessageStream { private _name: string; - constructor() { + constructor(streamOptions: DuplexOptions = {}) { // Kudos: https://stackoverflow.com/a/18002694 if ( typeof self === 'undefined' || @@ -29,7 +30,7 @@ export class WebWorkerPostMessageStream extends BasePostMessageStream { ); } - super(); + super(streamOptions); this._name = DEDICATED_WORKER_NAME; self.addEventListener('message', this._onMessage.bind(this) as any); diff --git a/src/node-process/ProcessMessageStream.ts b/src/node-process/ProcessMessageStream.ts index 6202e51..f62035c 100644 --- a/src/node-process/ProcessMessageStream.ts +++ b/src/node-process/ProcessMessageStream.ts @@ -1,3 +1,4 @@ +import type { DuplexOptions } from 'readable-stream'; import { BasePostMessageStream } from '../BasePostMessageStream'; import { isValidStreamMessage, StreamData } from '../utils'; @@ -5,8 +6,8 @@ import { isValidStreamMessage, StreamData } from '../utils'; * Child process-side Node.js `child_process` stream. */ export class ProcessMessageStream extends BasePostMessageStream { - constructor() { - super(); + constructor(streamOptions: DuplexOptions = {}) { + super(streamOptions); if (typeof globalThis.process.send !== 'function') { throw new Error( diff --git a/src/node-process/ProcessParentMessageStream.ts b/src/node-process/ProcessParentMessageStream.ts index 22eaed6..320b472 100644 --- a/src/node-process/ProcessParentMessageStream.ts +++ b/src/node-process/ProcessParentMessageStream.ts @@ -1,8 +1,9 @@ import type { ChildProcess } from 'child_process'; +import type { DuplexOptions } from 'readable-stream'; import { BasePostMessageStream } from '../BasePostMessageStream'; import { isValidStreamMessage, StreamData } from '../utils'; -interface ProcessParentMessageStreamArgs { +interface ProcessParentMessageStreamArgs extends DuplexOptions { process: ChildProcess; } @@ -18,8 +19,8 @@ export class ProcessParentMessageStream extends BasePostMessageStream { * @param args - Options bag. * @param args.process - The process to communicate with. */ - constructor({ process }: ProcessParentMessageStreamArgs) { - super(); + constructor({ process, ...streamOptions }: ProcessParentMessageStreamArgs) { + super(streamOptions); this._process = process; this._onMessage = this._onMessage.bind(this); diff --git a/src/node-thread/ThreadMessageStream.ts b/src/node-thread/ThreadMessageStream.ts index 6fa3691..673ca4d 100644 --- a/src/node-thread/ThreadMessageStream.ts +++ b/src/node-thread/ThreadMessageStream.ts @@ -1,4 +1,5 @@ import { parentPort } from 'worker_threads'; +import type { DuplexOptions } from 'readable-stream'; import { BasePostMessageStream } from '../BasePostMessageStream'; import { isValidStreamMessage, StreamData } from '../utils'; @@ -8,8 +9,8 @@ import { isValidStreamMessage, StreamData } from '../utils'; export class ThreadMessageStream extends BasePostMessageStream { #parentPort: Exclude; - constructor() { - super(); + constructor(streamOptions: DuplexOptions = {}) { + super(streamOptions); if (!parentPort) { throw new Error( diff --git a/src/node-thread/ThreadParentMessageStream.ts b/src/node-thread/ThreadParentMessageStream.ts index 6ab1138..38dcb95 100644 --- a/src/node-thread/ThreadParentMessageStream.ts +++ b/src/node-thread/ThreadParentMessageStream.ts @@ -1,8 +1,9 @@ import { Worker } from 'worker_threads'; +import type { DuplexOptions } from 'readable-stream'; import { BasePostMessageStream } from '../BasePostMessageStream'; import { isValidStreamMessage, StreamData } from '../utils'; -interface ThreadParentMessageStreamArgs { +interface ThreadParentMessageStreamArgs extends DuplexOptions { thread: Worker; } @@ -18,8 +19,8 @@ export class ThreadParentMessageStream extends BasePostMessageStream { * @param args - Options bag. * @param args.thread - The thread to communicate with. */ - constructor({ thread }: ThreadParentMessageStreamArgs) { - super(); + constructor({ thread, ...streamOptions }: ThreadParentMessageStreamArgs) { + super(streamOptions); this._thread = thread; this._onMessage = this._onMessage.bind(this); diff --git a/src/runtime/BrowserRuntimePostMessageStream.ts b/src/runtime/BrowserRuntimePostMessageStream.ts index 335d3ab..ed1766a 100644 --- a/src/runtime/BrowserRuntimePostMessageStream.ts +++ b/src/runtime/BrowserRuntimePostMessageStream.ts @@ -1,10 +1,11 @@ +import type { DuplexOptions } from 'readable-stream'; import { BasePostMessageStream, PostMessageEvent, } from '../BasePostMessageStream'; import { isValidStreamMessage } from '../utils'; -export interface BrowserRuntimePostMessageStreamArgs { +export interface BrowserRuntimePostMessageStreamArgs extends DuplexOptions { name: string; target: string; } @@ -26,8 +27,12 @@ export class BrowserRuntimePostMessageStream extends BasePostMessageStream { * multiple streams sharing the same runtime. * @param args.target - The name of the stream to exchange messages with. */ - constructor({ name, target }: BrowserRuntimePostMessageStreamArgs) { - super(); + constructor({ + name, + target, + ...streamOptions + }: BrowserRuntimePostMessageStreamArgs) { + super(streamOptions); this.#name = name; this.#target = target; diff --git a/src/window/WindowPostMessageStream.test.ts b/src/window/WindowPostMessageStream.test.ts index 536ddea..9233b71 100644 --- a/src/window/WindowPostMessageStream.test.ts +++ b/src/window/WindowPostMessageStream.test.ts @@ -1,6 +1,24 @@ import { WindowPostMessageStream } from './WindowPostMessageStream'; describe('WindowPostMessageStream', () => { + it('can override base stream options', () => { + const pms = new WindowPostMessageStream({ + name: 'foo', + target: 'bar', + encoding: 'ucs2', + objectMode: false, + }); + expect(pms._readableState.encoding).toBe('ucs2'); + expect(pms._readableState.objectMode).toBe(false); + expect(pms._writableState.objectMode).toBe(false); + }); + + it('can be instantiated with default options', () => { + const pms = new WindowPostMessageStream({ name: 'foo', target: 'bar' }); + expect(pms._readableState.objectMode).toBe(true); + expect(pms._writableState.objectMode).toBe(true); + }); + it('throws if window.postMessage is not a function', () => { const originalPostMessage = window.postMessage; (window as any).postMessage = undefined; diff --git a/src/window/WindowPostMessageStream.ts b/src/window/WindowPostMessageStream.ts index 76df938..81a64f3 100644 --- a/src/window/WindowPostMessageStream.ts +++ b/src/window/WindowPostMessageStream.ts @@ -1,11 +1,12 @@ import { assert } from '@metamask/utils'; +import type { DuplexOptions } from 'readable-stream'; import { BasePostMessageStream, PostMessageEvent, } from '../BasePostMessageStream'; import { isValidStreamMessage } from '../utils'; -interface WindowPostMessageStreamArgs { +interface WindowPostMessageStreamArgs extends DuplexOptions { name: string; target: string; targetOrigin?: string; @@ -56,8 +57,9 @@ export class WindowPostMessageStream extends BasePostMessageStream { target, targetOrigin = location.origin, targetWindow = window, + ...streamOptions }: WindowPostMessageStreamArgs) { - super(); + super(streamOptions); if ( typeof window === 'undefined' ||