A templating language that looks like Lisp and compiles to HTML
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

compiler.js 1.9KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. module.exports = class Compiler {
  2. constructor(tree, context) {
  3. this.tree = tree
  4. this.context = context
  5. this.result = ''
  6. }
  7. compile() {
  8. const selfClosingTags = [
  9. 'area',
  10. 'base',
  11. 'br',
  12. 'col',
  13. 'command',
  14. 'embed',
  15. 'hr',
  16. 'img',
  17. 'input',
  18. 'keygen',
  19. 'link',
  20. 'menuitem',
  21. 'meta',
  22. 'param',
  23. 'source',
  24. 'track',
  25. 'wbr',
  26. ]
  27. this.tree.forEach(node => {
  28. if (node.type === 'functionCall') {
  29. const attributes = node.args.map(
  30. arg =>
  31. `${arg.attributeName}="${this.compileAttribute(
  32. arg.attributeValue,
  33. )}"`,
  34. )
  35. const compiler = new Compiler(node.subtree, this.context)
  36. const content = compiler.compile()
  37. this.result += `<${node.functionName}${
  38. attributes.length ? ' ' : ''
  39. }${attributes.join(' ')}>`
  40. if (content) {
  41. this.result += content
  42. }
  43. if (!selfClosingTags.includes(node.functionName)) {
  44. this.result += `</${node.functionName}>`
  45. }
  46. } else if (node.type === 'string') {
  47. this.result += node.content
  48. } else if (node.type === 'identifier') {
  49. this.result += this.lookup(node.name)
  50. } else if (node.type === 'each') {
  51. const symbol = node.symbol.value
  52. const subject = this.lookup(node.subject.name)
  53. subject.forEach(item => {
  54. let context = {}
  55. context[symbol] = item
  56. const compiler = new Compiler([node.body], context)
  57. this.result += compiler.compile()
  58. })
  59. }
  60. })
  61. return this.result.trim()
  62. }
  63. compileAttribute(attribute) {
  64. if (attribute.type === 'string') {
  65. return attribute.content
  66. } else if (attribute.type === 'identifier') {
  67. return this.lookup(attribute.name)
  68. }
  69. }
  70. lookup(name) {
  71. return this.context[name]
  72. }
  73. }