Files
scriptc/tests/corpus/7244-objectmode-subclasses.ts
T
Chris Tate 67247dd26b Support objectMode streams with any value as a chunk
Readable, Writable, Duplex, Transform and PassThrough take the
objectMode option, and a Duplex, Transform or PassThrough the
readableObjectMode and writableObjectMode options, as true or false
literals in an options object literal or in an options value. An
object-mode side holds any value that converts to a checked-dynamic
value: push, unshift, write, end, pipe, pipeline, for await, 'data'
listeners, Readable.from and the transform callback carry values in
TypeScript and JavaScript, and constructor-function streams and options
held in variables do the same. The object-mode high-water mark counts
values and defaults to 16. A readable buffer that mixes strings, Buffers
and other values holds them all, and push(undefined) and other values on
a byte-mode stream report ERR_INVALID_ARG_TYPE through 'error', as in
Node.

In typed code a write or transform callback, or a _write or _transform
method, may declare its chunk with any such type, which converts when
the callback runs. Writes pass the encoding argument to _write and
_transform as Node does: undefined when absent, null when a callback
took its place, otherwise the value unchanged. A parameter declared
string | null | undefined receives that value and one declared string
receives "" for undefined and null. write(chunk, encoding) on a
byte-mode stream encodes a string chunk with any known encoding and
throws ERR_UNKNOWN_ENCODING for an unknown one. Readable.from takes
typed Maps and Sets of any such value, and arrays that mix strings and
Buffers.

for await over a readable-only stream that will emit 'close' now ends
after 'close', as Node's eos does. Buffered writes that complete inside
clearBuffer run their callbacks in order, and 'finish' waits for a
deferred afterWrite that carries a callback, as Node's pendingcb does,
unless a _final callback schedules it.

The 'data' listener adapters take three slots and write and transform
callbacks read their chunk and encoding through runtime accessors, so
RUNTIME_ABI_VERSION is now 26.
2026-10-22 04:21:55 -05:00

80 lines
2.1 KiB
TypeScript

// Typed object-mode stream subclasses: Transform, Writable and Readable
// classes that pass objectMode to super(), _transform/_write/_read with
// record chunks, encoding parameters typed string | null | undefined, and
// push() of records and other values.
import { Readable, Transform, Writable } from "node:stream";
import { pipeline } from "node:stream/promises";
interface Order {
id: number;
items: string[];
}
interface Summary {
id: number;
count: number;
}
class Orders extends Readable {
private next = 1;
constructor() {
super({ objectMode: true });
}
_read(): void {
if (this.next > 3) {
this.push(null);
return;
}
const id = this.next++;
this.push({ id, items: Array.from({ length: id }, (_, i) => `item${i}`) });
}
}
class Summarize extends Transform {
constructor() {
super({ objectMode: true });
}
_transform(
order: Order,
encoding: string | null | undefined,
cb: (err: Error | null, data?: Summary) => void,
): void {
console.log("summarize", order.id, encoding);
cb(null, { id: order.id, count: order.items.length });
}
}
class Report extends Writable {
lines: string[] = [];
constructor() {
super({ objectMode: true, highWaterMark: 1 });
}
_write(s: Summary, _encoding: string, cb: (err?: Error | null) => void): void {
this.lines.push(`#${s.id}=${s.count}`);
cb();
}
}
async function main(): Promise<void> {
const report = new Report();
console.log("report", report.writableObjectMode, report.writableHighWaterMark);
await pipeline(new Orders(), new Summarize(), report);
console.log("lines", report.lines.join(" "));
const direct = new Summarize();
direct.on("data", (s: Summary) => console.log("direct", s.id, s.count));
direct.write({ id: 9, items: ["a"] }, "utf8");
direct.write({ id: 10, items: [] }, () => console.log("written"));
direct.end();
const values = new Readable({ objectMode: true, read() {} });
values.push(1.5);
values.push("text");
values.push([1, 2]);
values.push(null);
const seen: string[] = [];
for await (const v of values) seen.push(JSON.stringify(v));
console.log("values", seen.join(" "));
}
main();