| 42 | #transform; |
| 43 | |
| 44 | constructor() { |
| 45 | this.#handle = new TextEncoder(); |
| 46 | this.#transform = new TransformStream({ |
| 47 | transform: (chunk, controller) => { |
| 48 | // https://encoding.spec.whatwg.org/#encode-and-enqueue-a-chunk |
| 49 | chunk = String(chunk); |
| 50 | let finalChunk = ''; |
| 51 | for (let i = 0; i < chunk.length; i++) { |
| 52 | const item = chunk[i]; |
| 53 | const codeUnit = StringPrototypeCharCodeAt(item, 0); |
| 54 | if (this.#pendingHighSurrogate !== null) { |
| 55 | const highSurrogate = this.#pendingHighSurrogate; |
| 56 | this.#pendingHighSurrogate = null; |
| 57 | if (0xDC00 <= codeUnit && codeUnit <= 0xDFFF) { |
| 58 | finalChunk += highSurrogate + item; |
| 59 | continue; |
| 60 | } |
| 61 | finalChunk += '\uFFFD'; |
| 62 | } |
| 63 | if (0xD800 <= codeUnit && codeUnit <= 0xDBFF) { |
| 64 | this.#pendingHighSurrogate = item; |
| 65 | continue; |
| 66 | } |
| 67 | if (0xDC00 <= codeUnit && codeUnit <= 0xDFFF) { |
| 68 | finalChunk += '\uFFFD'; |
| 69 | continue; |
| 70 | } |
| 71 | finalChunk += item; |
| 72 | } |
| 73 | if (finalChunk) { |
| 74 | const value = this.#handle.encode(finalChunk); |
| 75 | controller.enqueue(value); |
| 76 | } |
| 77 | }, |
| 78 | flush: (controller) => { |
| 79 | // https://encoding.spec.whatwg.org/#encode-and-flush |
| 80 | if (this.#pendingHighSurrogate !== null) { |
| 81 | controller.enqueue(new Uint8Array([0xEF, 0xBF, 0xBD])); |
| 82 | } |
| 83 | }, |
| 84 | }); |
| 85 | } |
| 86 | |
| 87 | /** |
| 88 | * @readonly |