mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-28 06:53:42 +08:00
Node converts a string chunk with Buffer.from(chunk, encoding) and
returns Buffer.concat for read(n), so every byte chunk user code
receives from a non-object-mode stream is a Buffer. The runtime made
these chunks as plain Uint8Array storage. A typed write(), transform()
or 'data' callback then printed String(chunk), `${chunk}` and
chunk + "" as comma-separated bytes (97,98) instead of the text, and
read(n) and read() after unshift(string) returned non-Buffer values to
untyped code.
The chunks the stream creates now carry the Buffer brand: write() and
push() of a string (with or without an encoding), transform output given
as a string (the callback or this.push), unshift() of a string, and the
concatenation read(n) returns.
Corpus 5445 (typed callbacks, pipeline and stream/promises pipeline)
and 5446 (untyped code, Buffer.isBuffer at each boundary) check this
against Node.
85 lines
2.4 KiB
TypeScript
85 lines
2.4 KiB
TypeScript
// Chunks a stream creates from strings are Buffers, as in Node: write()
|
|
// and push() of a string, push() with an encoding, transform output given
|
|
// as a string (callback or this.push), the concatenation read(n) returns,
|
|
// and unshift() of a string. Typed callbacks receive them as Buffer, so
|
|
// String(), template literals and + print the text.
|
|
import { PassThrough, Readable, Transform, Writable, pipeline } from "node:stream";
|
|
import { pipeline as pipelinePromise } from "node:stream/promises";
|
|
|
|
const show = (where: string, c: Buffer): void => console.log(where, String(c), `${c}`, c + "", c.length);
|
|
|
|
const w = new Writable({
|
|
write(c: Buffer, _e, cb) {
|
|
show("write", c);
|
|
cb();
|
|
},
|
|
});
|
|
w.write("ab");
|
|
w.write(Buffer.from("cd"));
|
|
w.write("é");
|
|
w.end();
|
|
|
|
const r = new Readable({ read() {} });
|
|
r.on("data", (c: Buffer) => show("push", c));
|
|
r.push("ef");
|
|
r.push(null);
|
|
|
|
const encoded = new Readable({ read() {} });
|
|
encoded.on("data", (c: Buffer) => show("push-base64", c));
|
|
encoded.push("aGk=", "base64");
|
|
encoded.push(null);
|
|
|
|
const upper = new Transform({
|
|
transform(c: Buffer, _e, cb) {
|
|
cb(null, String(c).toUpperCase());
|
|
},
|
|
});
|
|
upper.on("data", (c: Buffer) => show("transform-callback", c));
|
|
upper.write("ij");
|
|
upper.end();
|
|
|
|
const exclaim = new Transform({
|
|
transform(c: Buffer, _e, cb) {
|
|
this.push(String(c) + "!");
|
|
cb();
|
|
},
|
|
});
|
|
exclaim.on("data", (c: Buffer) => show("transform-push", c));
|
|
exclaim.write("kl");
|
|
exclaim.end();
|
|
|
|
const pass = new PassThrough();
|
|
pass.on("data", (c: Buffer) => show("passthrough", c));
|
|
pass.write("mn");
|
|
pass.end();
|
|
|
|
const buffered = new Readable({ read() {} });
|
|
buffered.push("op");
|
|
buffered.push("qr");
|
|
buffered.push(null);
|
|
buffered.once("readable", () => {
|
|
show("read(3)", buffered.read(3) as Buffer);
|
|
buffered.unshift("z");
|
|
show("after-unshift", buffered.read() as Buffer);
|
|
});
|
|
|
|
const collected: string[] = [];
|
|
const sink = new Writable({
|
|
write(c: Buffer, _e, cb) {
|
|
collected.push(String(c));
|
|
cb();
|
|
},
|
|
});
|
|
pipeline(Readable.from(["s", "t"]), sink, (err: NodeJS.ErrnoException | null) => {
|
|
console.log("pipeline", err ?? null, collected.join(""));
|
|
});
|
|
|
|
const promised: string[] = [];
|
|
const promiseSink = new Writable({
|
|
write(c: Buffer, _e, cb) {
|
|
promised.push(`${c}`);
|
|
cb();
|
|
},
|
|
});
|
|
void pipelinePromise(Readable.from(["u", "v"]), promiseSink).then(() => console.log("pipeline promise", promised.join("")));
|