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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  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. }