diff --git a/common/changes/@yume-chan/stream-extra/main_2024-05-10-00-32.json b/common/changes/@yume-chan/stream-extra/main_2024-05-10-00-32.json new file mode 100644 index 00000000..8e9845ef --- /dev/null +++ b/common/changes/@yume-chan/stream-extra/main_2024-05-10-00-32.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@yume-chan/stream-extra", + "comment": "Re-export global `TextDecoderStream` instead of implementing our own one which doesn't work correctly in stream mode", + "type": "none" + } + ], + "packageName": "@yume-chan/stream-extra" +} diff --git a/libraries/adb-scrcpy/src/client.ts b/libraries/adb-scrcpy/src/client.ts index c416abf9..d8236a26 100644 --- a/libraries/adb-scrcpy/src/client.ts +++ b/libraries/adb-scrcpy/src/client.ts @@ -29,10 +29,10 @@ import type { import { AbortController, BufferedReadableStream, - DecodeUtf8Stream, InspectStream, PushReadableStream, SplitStringStream, + TextDecoderStream, WritableStream, } from "@yume-chan/stream-extra"; @@ -158,7 +158,7 @@ export class AdbScrcpyClient { ); const stdout = process.stdout - .pipeThrough(new DecodeUtf8Stream()) + .pipeThrough(new TextDecoderStream()) .pipeThrough(new SplitStringStream("\n")); // Must read all streams, otherwise the whole connection will be blocked. diff --git a/libraries/adb/src/adb.ts b/libraries/adb/src/adb.ts index 56cceb16..a43ffe73 100644 --- a/libraries/adb/src/adb.ts +++ b/libraries/adb/src/adb.ts @@ -2,7 +2,7 @@ import type { MaybeConsumable, ReadableWritablePair, } from "@yume-chan/stream-extra"; -import { ConcatStringStream, DecodeUtf8Stream } from "@yume-chan/stream-extra"; +import { ConcatStringStream, TextDecoderStream } from "@yume-chan/stream-extra"; import type { ValueOrPromise } from "@yume-chan/struct"; import type { AdbBanner } from "./banner.js"; @@ -112,7 +112,7 @@ export class Adb implements Closeable { async createSocketAndWait(service: string): Promise { const socket = await this.createSocket(service); return await socket.readable - .pipeThrough(new DecodeUtf8Stream()) + .pipeThrough(new TextDecoderStream()) .pipeThrough(new ConcatStringStream()); } diff --git a/libraries/adb/src/commands/subprocess/command.ts b/libraries/adb/src/commands/subprocess/command.ts index 54cbea74..27f8f80b 100644 --- a/libraries/adb/src/commands/subprocess/command.ts +++ b/libraries/adb/src/commands/subprocess/command.ts @@ -1,4 +1,4 @@ -import { ConcatStringStream, DecodeUtf8Stream } from "@yume-chan/stream-extra"; +import { ConcatStringStream, TextDecoderStream } from "@yume-chan/stream-extra"; import { AdbCommandBase } from "../base.js"; @@ -112,10 +112,10 @@ export class AdbSubprocess extends AdbCommandBase { const [stdout, stderr, exitCode] = await Promise.all([ process.stdout - .pipeThrough(new DecodeUtf8Stream()) + .pipeThrough(new TextDecoderStream()) .pipeThrough(new ConcatStringStream()), process.stderr - .pipeThrough(new DecodeUtf8Stream()) + .pipeThrough(new TextDecoderStream()) .pipeThrough(new ConcatStringStream()), process.exit, ]); diff --git a/libraries/android-bin/src/am.ts b/libraries/android-bin/src/am.ts index 450b21f9..f762fff2 100644 --- a/libraries/android-bin/src/am.ts +++ b/libraries/android-bin/src/am.ts @@ -1,6 +1,6 @@ import type { Adb } from "@yume-chan/adb"; import { AdbCommandBase } from "@yume-chan/adb"; -import { ConcatStringStream, DecodeUtf8Stream } from "@yume-chan/stream-extra"; +import { ConcatStringStream, TextDecoderStream } from "@yume-chan/stream-extra"; import { Cmd } from "./cmd.js"; import type { IntentBuilder } from "./intent.js"; @@ -53,7 +53,7 @@ export class ActivityManager extends AdbCommandBase { const process = await this.#cmdOrSubprocess(args); const output = await process.stdout - .pipeThrough(new DecodeUtf8Stream()) + .pipeThrough(new TextDecoderStream()) .pipeThrough(new ConcatStringStream()) .then((output) => output.trim()); diff --git a/libraries/android-bin/src/bu.ts b/libraries/android-bin/src/bu.ts index 4610b011..7f0e45ca 100644 --- a/libraries/android-bin/src/bu.ts +++ b/libraries/android-bin/src/bu.ts @@ -1,6 +1,6 @@ import { AdbCommandBase } from "@yume-chan/adb"; import type { MaybeConsumable, ReadableStream } from "@yume-chan/stream-extra"; -import { ConcatStringStream, DecodeUtf8Stream } from "@yume-chan/stream-extra"; +import { ConcatStringStream, TextDecoderStream } from "@yume-chan/stream-extra"; export interface AdbBackupOptions { user: number; @@ -71,7 +71,7 @@ export class AdbBackup extends AdbCommandBase { const process = await this.adb.subprocess.spawn(args); const [output] = await Promise.all([ process.stdout - .pipeThrough(new DecodeUtf8Stream()) + .pipeThrough(new TextDecoderStream()) .pipeThrough(new ConcatStringStream()), options.file.pipeTo(process.stdin), ]); diff --git a/libraries/android-bin/src/bug-report.ts b/libraries/android-bin/src/bug-report.ts index 91f94845..ec956ff5 100644 --- a/libraries/android-bin/src/bug-report.ts +++ b/libraries/android-bin/src/bug-report.ts @@ -6,9 +6,9 @@ import { AdbCommandBase, AdbSubprocessShellProtocol } from "@yume-chan/adb"; import type { AbortSignal, ReadableStream } from "@yume-chan/stream-extra"; import { AbortController, - DecodeUtf8Stream, PushReadableStream, SplitStringStream, + TextDecoderStream, WrapReadableStream, WritableStream, } from "@yume-chan/stream-extra"; @@ -212,7 +212,7 @@ export class BugReport extends AdbCommandBase { let error: string | undefined; await process.stdout - .pipeThrough(new DecodeUtf8Stream()) + .pipeThrough(new TextDecoderStream()) .pipeThrough(new SplitStringStream("\n")) .pipeTo( new WritableStream({ @@ -278,7 +278,7 @@ export class BugReport extends AdbCommandBase { controller.error(e); }); process.stderr - .pipeThrough(new DecodeUtf8Stream()) + .pipeThrough(new TextDecoderStream()) .pipeTo( new WritableStream({ write(chunk) { diff --git a/libraries/android-bin/src/cmd.ts b/libraries/android-bin/src/cmd.ts index 7bcf5d4c..5588f563 100644 --- a/libraries/android-bin/src/cmd.ts +++ b/libraries/android-bin/src/cmd.ts @@ -10,7 +10,7 @@ import { AdbSubprocessNoneProtocol, AdbSubprocessShellProtocol, } from "@yume-chan/adb"; -import { ConcatStringStream, DecodeUtf8Stream } from "@yume-chan/stream-extra"; +import { ConcatStringStream, TextDecoderStream } from "@yume-chan/stream-extra"; export class Cmd extends AdbCommandBase { #supportsShellV2: boolean; @@ -84,10 +84,10 @@ export class Cmd extends AdbCommandBase { const [stdout, stderr, exitCode] = await Promise.all([ process.stdout - .pipeThrough(new DecodeUtf8Stream()) + .pipeThrough(new TextDecoderStream()) .pipeThrough(new ConcatStringStream()), process.stderr - .pipeThrough(new DecodeUtf8Stream()) + .pipeThrough(new TextDecoderStream()) .pipeThrough(new ConcatStringStream()), process.exit, ]); diff --git a/libraries/android-bin/src/logcat.ts b/libraries/android-bin/src/logcat.ts index b7473442..77985d2a 100644 --- a/libraries/android-bin/src/logcat.ts +++ b/libraries/android-bin/src/logcat.ts @@ -5,8 +5,8 @@ import { AdbCommandBase, AdbSubprocessNoneProtocol } from "@yume-chan/adb"; import type { ReadableStream } from "@yume-chan/stream-extra"; import { BufferedTransformStream, - DecodeUtf8Stream, SplitStringStream, + TextDecoderStream, WrapReadableStream, WritableStream, } from "@yume-chan/stream-extra"; @@ -421,7 +421,7 @@ export class Logcat extends AdbCommandBase { const result: LogSize[] = []; await stdout - .pipeThrough(new DecodeUtf8Stream()) + .pipeThrough(new TextDecoderStream()) .pipeThrough(new SplitStringStream("\n")) .pipeTo( new WritableStream({ diff --git a/libraries/android-bin/src/pm.ts b/libraries/android-bin/src/pm.ts index f874b579..1d00f6fe 100644 --- a/libraries/android-bin/src/pm.ts +++ b/libraries/android-bin/src/pm.ts @@ -8,8 +8,8 @@ import { AdbCommandBase, escapeArg } from "@yume-chan/adb"; import type { MaybeConsumable, ReadableStream } from "@yume-chan/stream-extra"; import { ConcatStringStream, - DecodeUtf8Stream, SplitStringStream, + TextDecoderStream, } from "@yume-chan/stream-extra"; import { Cmd } from "./cmd.js"; @@ -352,7 +352,7 @@ export class PackageManager extends AdbCommandBase { const process = await this.#cmd.spawn(false, "package", ...args); const output = process.stdout - .pipeThrough(new DecodeUtf8Stream()) + .pipeThrough(new TextDecoderStream()) .pipeThrough(new ConcatStringStream()) .then((output) => output.trim()); @@ -440,7 +440,7 @@ export class PackageManager extends AdbCommandBase { const process = await this.#cmdOrSubprocess(args); const reader = process.stdout - .pipeThrough(new DecodeUtf8Stream()) + .pipeThrough(new TextDecoderStream()) .pipeThrough(new SplitStringStream("\n")) .getReader(); while (true) { @@ -468,7 +468,7 @@ export class PackageManager extends AdbCommandBase { const process = await this.#cmdOrSubprocess(args); const output = await process.stdout - .pipeThrough(new DecodeUtf8Stream()) + .pipeThrough(new TextDecoderStream()) .pipeThrough(new ConcatStringStream()) .then((output) => output.trim()); if (output !== "Success") { @@ -489,7 +489,7 @@ export class PackageManager extends AdbCommandBase { const process = await this.#cmdOrSubprocess(args); const output = await process.stdout - .pipeThrough(new DecodeUtf8Stream()) + .pipeThrough(new TextDecoderStream()) .pipeThrough(new ConcatStringStream()) .then((output) => output.trim()); @@ -515,7 +515,7 @@ export class PackageManager extends AdbCommandBase { const process = await this.#cmdOrSubprocess(args); const output = await process.stdout - .pipeThrough(new DecodeUtf8Stream()) + .pipeThrough(new TextDecoderStream()) .pipeThrough(new ConcatStringStream()) .then((output) => output.trim()); @@ -562,7 +562,7 @@ export class PackageManager extends AdbCommandBase { const process = await this.#cmdOrSubprocess(args); const output = process.stdout - .pipeThrough(new DecodeUtf8Stream()) + .pipeThrough(new TextDecoderStream()) .pipeThrough(new ConcatStringStream()) .then((output) => output.trim()); diff --git a/libraries/stream-extra/src/concat.ts b/libraries/stream-extra/src/concat.ts index 40650541..b605071a 100644 --- a/libraries/stream-extra/src/concat.ts +++ b/libraries/stream-extra/src/concat.ts @@ -82,8 +82,8 @@ export interface ConcatBufferReadableStream * A `TransformStream` that concatenates `Uint8Array`s. * * If you want to decode the result as string, - * prefer `.pipeThrough(new DecodeUtf8Stream()).pipeThrough(new ConcatStringStream())`, - * than `.pipeThough(new ConcatBufferStream()).pipeThrough(new DecodeUtf8Stream())`, + * prefer `.pipeThrough(new TextDecoderStream()).pipeThrough(new ConcatStringStream())`, + * than `.pipeThough(new ConcatBufferStream()).pipeThrough(new TextDecoderStream())`, * because of JavaScript engine optimizations, * concatenating strings is faster than concatenating `Uint8Array`s. */ diff --git a/libraries/stream-extra/src/decode-utf8.ts b/libraries/stream-extra/src/decode-utf8.ts deleted file mode 100644 index 875a9d1e..00000000 --- a/libraries/stream-extra/src/decode-utf8.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { decodeUtf8 } from "@yume-chan/struct"; - -import { TransformStream } from "./stream.js"; - -export class DecodeUtf8Stream extends TransformStream { - constructor() { - super({ - transform(chunk, controller) { - controller.enqueue(decodeUtf8(chunk)); - }, - }); - } -} diff --git a/libraries/stream-extra/src/encoding.ts b/libraries/stream-extra/src/encoding.ts new file mode 100644 index 00000000..380e8111 --- /dev/null +++ b/libraries/stream-extra/src/encoding.ts @@ -0,0 +1,39 @@ +import type { TransformStream } from "./stream.js"; + +export interface TextDecoderOptions { + fatal?: boolean; + ignoreBOM?: boolean; +} + +declare class TextDecoderStreamType extends TransformStream< + ArrayBufferView | ArrayBuffer, + string +> { + constructor(label?: string, options?: TextDecoderOptions); + + readonly encoding: string; + readonly fatal: boolean; + readonly ignoreBOM: boolean; +} + +declare class TextEncoderStreamType extends TransformStream< + string, + Uint8Array +> { + constructor(); + + readonly encoding: string; +} + +interface GlobalExtension { + TextDecoderStream: typeof TextDecoderStreamType; + TextEncoderStream: typeof TextEncoderStreamType; +} + +const Global = globalThis as unknown as GlobalExtension; + +export const TextDecoderStream = Global.TextDecoderStream; +export type TextDecoderStream = TextDecoderStreamType; + +export const TextEncoderStream = Global.TextEncoderStream; +export type TextEncoderStream = TextEncoderStreamType; diff --git a/libraries/stream-extra/src/index.ts b/libraries/stream-extra/src/index.ts index 9abc3361..f8c0fd4a 100644 --- a/libraries/stream-extra/src/index.ts +++ b/libraries/stream-extra/src/index.ts @@ -2,9 +2,9 @@ export * from "./buffered-transform.js"; export * from "./buffered.js"; export * from "./concat.js"; export * from "./consumable.js"; -export * from "./decode-utf8.js"; export * from "./distribution.js"; export * from "./duplex.js"; +export * from "./encoding.js"; export * from "./inspect.js"; export * from "./maybe-consumable.js"; export * from "./pipe-from.js";