Page MenuHomeSealhub

index.ts
No OneTemporary

index.ts

import { Readable } from "stream";
import pipeInto from "./pipe-into";
import { Slot } from "./slot";
import { Stringifiable, stringify } from "./stringify";
export { Slot } from "./slot";
export type Templatable =
| Stringifiable
| Slot
| (Stringifiable | Templatable | Promise<Templatable>)[];
async function* templateGen(
strings: TemplateStringsArray,
...params: Templatable[]
) {
for (let string of strings) {
yield string;
const param = params.shift();
yield param;
}
yield null;
}
class TempStream extends Readable {
is_piping_substream = false;
is_handling_array = false;
id = Math.random();
constructor(public generator: ReturnType<typeof templateGen>) {
super();
}
_read() {
if (this.is_piping_substream || this.is_handling_array) {
return;
}
const next = this.generator.next();
next.then(async (result) => {
this.handleResult(
result,
(data) => {
this.push(data);
},
() => this.emit("end")
);
}).catch(console.error);
}
async handleSlot(slot: Slot, push: (data: any) => void) {
let suffix = "";
let changed = slot.changed;
let finished = false;
slot.on("change", () => (changed = true));
let new_result;
while (!finished && !changed) {
new_result = await this.generator.next();
await this.handleResult(
new_result,
(data) => {
if (data === null) return;
suffix += data;
},
() => (finished = true)
);
}
if (!changed) {
console.warn(
"Warning: tempstream needed to wait until the end of the stream to ensure it's ok to use the default value for a slot: '${slot.value}'. The defaut value is only there for safety. It's best to assign a value to a slot as soon as possible during rendering, so the data after the slot can begin to be sent."
);
}
push(slot.value + suffix);
}
async handleSingleResult(subvalue: unknown, push: (data: any) => void) {
if (subvalue instanceof Readable) {
this.is_piping_substream = true;
await pipeInto(subvalue, push).then(() => {
this.is_piping_substream = false;
this._read();
});
} else if (subvalue instanceof Slot) {
await this.handleSlot(subvalue, push);
} else {
push(await stringify(subvalue as Stringifiable));
}
}
async serializePluralResult(value: unknown, push: (data: any) => void) {
value = await value;
if (Array.isArray(value)) {
this.is_handling_array = true;
for (const [index, subvalue] of Object.entries(value)) {
await this.serializePluralResult(subvalue, push);
if (parseInt(index) < value.length - 1) push("\n");
}
this.is_handling_array = false;
this._read();
} else {
await this.handleSingleResult(value, push);
}
}
async handleResult(
result: IteratorResult<unknown>,
push: (data: any) => void,
end: () => void
) {
if (result.done) {
push(null);
end();
}
const value = await result.value;
await this.serializePluralResult(value, push);
}
push(data: unknown): boolean {
super.push(data);
return true;
}
}
export function tempstream(
strings: TemplateStringsArray,
...params: Templatable[]
): Readable {
return new TempStream(templateGen(strings, ...params));
}

File Metadata

Mime Type
text/x-java
Expires
Sun, Nov 24, 02:15 (22 h, 38 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
548083
Default Alt Text
index.ts (3 KB)

Event Timeline