UNPKG

edgerender-yatl

Version:

Yet Another Template Language

134 lines 4.55 kB
"use strict"; 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