edgerender-yatl
Version:
Yet Another Template Language
134 lines • 4.55 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Renderer = exports.render_template = void 0;
const expressions_1 = require("./expressions");
async function render_template(template, context, functions) {
const r = new Renderer(functions);
return await r.render(template, context);
}
exports.render_template = render_template;
class Renderer {
constructor(functions) {
this.functions = functions;
}
async render(template, context) {
let s = '';
for (const chunk of template) {
const v = await this.render_chunk(chunk, context);
if (v) {
s += v;
}
}
return s;
}
async render_chunk(chunk, context) {
switch (chunk.type) {
case 'text':
return chunk.text;
case 'tag':
case 'component':
return await this.render_element(chunk, context);
case 'doctype':
return `<!DOCTYPE ${chunk.doctype}>`;
default:
return await expressions_1.evaluate_as_str(chunk, context, this.functions);
}
}
async render_element(chunk, context) {
const if_ = chunk.if;
if (if_ != undefined) {
const v = await expressions_1.evaluate_as_bool(if_, context, this.functions);
if (!v) {
return null;
}
}
const render = (context) => {
if (chunk.type == 'tag') {
return this.render_tag(chunk, context);
}
else {
return this.render_component(chunk, context);
}
};
const for_ = chunk.for;
if (for_ == undefined) {
return await render(context);
}
else {
const contexts = await expressions_1.evaluate_as_loop(for_, chunk.for_names, context, this.functions);
let index = 1;
const parts = [];
for (const loop_names_context of contexts) {
const loop = {
index,
first: index == 1,
last: index == contexts.length,
};
const v = await render({ ...context, ...loop_names_context, loop });
if (v) {
parts.push(v);
}
index++;
}
let join_with = '\n' + ' '.repeat(chunk.loc.col - 1);
if (chunk.for_join) {
join_with = await this.evaluate_attr_value(chunk.for_join, context);
}
return parts.join(join_with);
}
}
async render_tag(tag, context) {
const new_context = { ...context };
const { name, body, set_attributes, attributes, fragment } = tag;
if (set_attributes) {
for (const { name, value } of set_attributes) {
new_context[name] = await this.evaluate_attr_value(value, context);
}
}
if (fragment) {
return body ? await this.render(body, new_context) : null;
}
let attrs = '';
if (attributes) {
for (const { name, value } of attributes) {
const v = await this.evaluate_attr_value(value, context);
attrs += ` ${name}="${v}"`;
}
}
if (body) {
const body_str = await this.render(body, new_context);
return `<${name}${attrs}>${body_str}</${name}>`;
}
else {
return `<${name}${attrs}/>`;
}
}
async render_component(comp, context) {
const new_context = { ...context };
const { body, props, children } = comp;
if (props) {
for (const { name, value } of props) {
new_context[name] = await this.evaluate_attr_value(value, context);
}
}
if (children) {
new_context.children = await this.render(children, new_context);
}
return await this.render(body, new_context);
}
async evaluate_attr_value(value, context) {
// TODO escaping
let s = '';
for (const chunk of value) {
if (chunk.type == 'text') {
s += chunk.text;
}
else {
s += await expressions_1.evaluate_as_str(chunk, context, this.functions);
}
}
return s;
}
}
exports.Renderer = Renderer;
//# sourceMappingURL=render.js.map