module.exports = class Compiler { constructor(tree, context) { this.tree = tree this.context = context this.result = '' } compile() { this.tree.forEach(node => { if (node.type === 'functionCall') { const attributes = node.args.map( arg => `${arg.attributeName}="${this.compileAttribute( arg.attributeValue, )}"`, ) const compiler = new Compiler(node.subtree, this.context) const content = compiler.compile() if (node.functionName) { this.result += `<${node.functionName}${ attributes.length ? ' ' : '' }${attributes.join(' ')}>${content}` } else { this.result += content } } else if (node.type === 'string') { this.result += node.content } else if (node.type === 'identifier') { this.result += this.lookup(node.name) } else if (node.type === 'each') { const symbol = node.symbol.value const subject = this.lookup(node.subject.name) subject.forEach(item => { let context = {} context[symbol] = item const compiler = new Compiler([node.body], context) this.result += compiler.compile() }) } }) return this.result.trim() } compileAttribute(attribute) { if (attribute.type === 'string') { return attribute.content } else if (attribute.type === 'identifier') { return this.lookup(attribute.name) } } lookup(name) { return this.context[name] } }