Page Menu
Home
Sealhub
Search
Configure Global Search
Log In
Files
F10360011
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
4 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/index.ts b/src/index.ts
index dabad54..11607bb 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,97 +1,98 @@
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;
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;
id = Math.random();
constructor(public generator: ReturnType<typeof templateGen>) {
super();
}
_read() {
if (this.is_piping_substream) {
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)
);
}
push(slot.value + suffix);
}
async handleResult(
result: IteratorResult<any>,
push: (data: any) => void,
end: () => void
) {
if (result.done) {
push(null);
end();
}
if (result.value instanceof Readable) {
this.is_piping_substream = true;
await pipeInto(result.value, push).then(() => {
this.is_piping_substream = false;
this._read();
});
} else if (result.value instanceof Slot) {
await this.handleSlot(result.value, push);
} else {
push(await stringify(result.value));
}
}
push(data: unknown): boolean {
super.push(data);
return true;
}
}
export function tempstream(
strings: TemplateStringsArray,
...params: Templatable[]
): Readable {
return new TempStream(templateGen(strings, ...params));
}
diff --git a/src/test.ts b/src/test.ts
index 40c4738..b27c83f 100644
--- a/src/test.ts
+++ b/src/test.ts
@@ -1,71 +1,79 @@
import assert from "assert";
import { Readable } from "stream";
import { promisify } from "util";
import { Templatable, tempstream } from ".";
import { Slot } from "./slot";
import streamToString from "./tostring";
const name = new Slot("noname");
const st = (time: number, cb: () => void) => setTimeout(cb, time);
const sleep = promisify(st);
// a test
function html(
strings: TemplateStringsArray,
...params: Templatable[]
): Readable {
const title = new Slot("Default page title");
setTimeout(() => title.set("Changed page title"), 3000);
console.error(
"try playing around with the above timeout. Weird things happen when you go to e.g. 3000"
);
// process.exit(1);
return tempstream/* HTML */ `<!DOCTYPE html>
<head>
<meta charset="utf-8" />
<title>${title}</title>
</head>
<body>
${tempstream(strings, ...params)}
</body> `;
}
// template`hello ${world}, and ${name}`.pipe(process.stdout);
describe("tempstream", () => {
it("renders properly in the basic case", async () => {
const list_items = Promise.resolve(
["one", "two", "three"].map((e) => `<li>${e}</li>`)
);
const title = new Slot("Default page title");
setTimeout(() => title.set("Changed page title"), 20);
const slept = sleep(100).then(() => "slept");
const result =
await streamToString(tempstream/* HTML */ `<!DOCTYPE html>
<head>
<meta charset="utf-8" />
<title>${title}</title>
</head>
<body>
hello World, I ${slept}.
<ul>
${list_items}
</ul>
</body> `);
assert.strictEqual(
result,
`<!DOCTYPE html>
<head>
<meta charset="utf-8" />
<title>Changed page title</title>
</head>
<body>
hello World, I slept.
<ul>
<li>one</li>
<li>two</li>
<li>three</li>
</ul>
</body> `
);
});
+
+ it("doesn't add unecessary 'null' when encountering an unresolved slot", async () => {
+ const title = new Slot("unchanged");
+ const result = await streamToString(
+ tempstream`<title>${title}</title>`
+ );
+ assert.strictEqual(result, `<title>unchanged</title>`);
+ });
});
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Nov 8, 03:41 (21 h, 4 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1033983
Default Alt Text
(4 KB)
Attached To
Mode
rSTREAM tempstream
Attached
Detach File
Event Timeline
Log In to Comment