-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
/
render-template.ts
65 lines (58 loc) · 2.16 KB
/
render-template.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import { markHTMLString } from '../../escape.js';
import { isPromise } from '../../util.js';
import { renderChild } from '../any.js';
import type { RenderDestination } from '../common.js';
import { renderToBufferDestination } from '../util.js';
const renderTemplateResultSym = Symbol.for('astro.renderTemplateResult');
// The return value when rendering a component.
// This is the result of calling render(), should this be named to RenderResult or...?
export class RenderTemplateResult {
public [renderTemplateResultSym] = true;
private htmlParts: TemplateStringsArray;
public expressions: any[];
private error: Error | undefined;
constructor(htmlParts: TemplateStringsArray, expressions: unknown[]) {
this.htmlParts = htmlParts;
this.error = undefined;
this.expressions = expressions.map((expression) => {
// Wrap Promise expressions so we can catch errors
// There can only be 1 error that we rethrow from an Astro component,
// so this keeps track of whether or not we have already done so.
if (isPromise(expression)) {
return Promise.resolve(expression).catch((err) => {
if (!this.error) {
this.error = err;
throw err;
}
});
}
return expression;
});
}
async render(destination: RenderDestination) {
// Render all expressions eagerly and in parallel
const expRenders = this.expressions.map((exp) => {
return renderToBufferDestination((bufferDestination) => {
// Skip render if falsy, except the number 0
if (exp || exp === 0) {
return renderChild(bufferDestination, exp);
}
});
});
for (let i = 0; i < this.htmlParts.length; i++) {
const html = this.htmlParts[i];
const expRender = expRenders[i];
destination.write(markHTMLString(html));
if (expRender) {
await expRender.renderToFinalDestination(destination);
}
}
}
}
// Determines if a component is an .astro component
export function isRenderTemplateResult(obj: unknown): obj is RenderTemplateResult {
return typeof obj === 'object' && !!(obj as any)[renderTemplateResultSym];
}
export function renderTemplate(htmlParts: TemplateStringsArray, ...expressions: any[]) {
return new RenderTemplateResult(htmlParts, expressions);
}