index.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. import { genEvents, addHandler } from './events'
  2. import { genModel } from './model'
  3. import {
  4. parseText,
  5. parseModifiers,
  6. removeModifiers,
  7. getAndRemoveAttr
  8. } from './helpers'
  9. const dirRE = /^v-|^@|^:/
  10. const bindRE = /^:|^v-bind:/
  11. const onRE = /^@|^v-on:/
  12. const mustUsePropsRE = /^(value|selected|checked|muted)$/
  13. export function generate (ast) {
  14. const code = ast ? genElement(ast) : '__h__("div")'
  15. return new Function(`with (this) { return ${code}}`)
  16. }
  17. function genElement (el, key) {
  18. let exp
  19. if ((exp = getAndRemoveAttr(el, 'v-for'))) {
  20. return genFor(el, exp)
  21. } else if ((exp = getAndRemoveAttr(el, 'v-if'))) {
  22. return genIf(el, exp)
  23. } else if (el.tag === 'template') {
  24. return genChildren(el)
  25. } else {
  26. return `__h__('${el.tag}', ${genData(el, key)}, ${genChildren(el)})`
  27. }
  28. }
  29. function genIf (el, exp) {
  30. return `(${exp}) ? ${genElement(el)} : null`
  31. }
  32. function genFor (el, exp) {
  33. const inMatch = exp.match(/([a-zA-Z_][\w]*)\s+(?:in|of)\s+(.*)/)
  34. if (!inMatch) {
  35. throw new Error('Invalid v-for expression: ' + exp)
  36. }
  37. const alias = inMatch[1].trim()
  38. exp = inMatch[2].trim()
  39. let key = getAndRemoveAttr(el, 'track-by')
  40. if (!key) {
  41. key = 'undefined'
  42. } else if (key !== '$index') {
  43. key = alias + '["' + key + '"]'
  44. }
  45. return `(${exp}) && (${exp}).map(function (${alias}, $index) {return ${genElement(el, key)}})`
  46. }
  47. function genData (el, key) {
  48. if (!el.attrs.length) {
  49. return '{}'
  50. }
  51. let data = '{'
  52. let attrs = 'attrs:{'
  53. let props = 'props:{'
  54. let events = {}
  55. let hasAttrs = false
  56. let hasProps = false
  57. let hasEvents = false
  58. // key
  59. if (key) {
  60. data += `key:${key},`
  61. }
  62. // class
  63. const classBinding = getAndRemoveAttr(el, ':class') || getAndRemoveAttr(el, 'v-bind:class')
  64. if (classBinding) {
  65. data += `class: ${classBinding},`
  66. }
  67. const staticClass = getAndRemoveAttr(el, 'class')
  68. if (staticClass) {
  69. data += `staticClass: "${staticClass}",`
  70. }
  71. // parent elements my need to add props to children
  72. if (el.props) {
  73. hasProps = true
  74. props += el.props + ','
  75. }
  76. // loop attributes
  77. for (let i = 0, l = el.attrs.length; i < l; i++) {
  78. let attr = el.attrs[i]
  79. let name = attr.name
  80. let value = attr.value
  81. if (dirRE.test(name)) {
  82. // modifiers
  83. const modifiers = parseModifiers(name)
  84. name = removeModifiers(name)
  85. if (bindRE.test(name)) {
  86. name = name.replace(bindRE, '')
  87. if (name === 'style') {
  88. data += `style: ${value},`
  89. } else if (mustUsePropsRE.test(name)) {
  90. hasProps = true
  91. props += `"${name}": (${value}),`
  92. } else {
  93. hasAttrs = true
  94. attrs += `"${name}": (${value}),`
  95. }
  96. } else if (onRE.test(name)) {
  97. hasEvents = true
  98. name = name.replace(onRE, '')
  99. addHandler(events, name, value, modifiers)
  100. } else if (name === 'v-model') {
  101. hasProps = hasEvents = true
  102. props += genModel(el, events, value, modifiers) + ','
  103. } else {
  104. // TODO: normal directives
  105. }
  106. } else {
  107. hasAttrs = true
  108. attrs += `"${name}": (${JSON.stringify(attr.value)}),`
  109. }
  110. }
  111. if (hasAttrs) {
  112. data += attrs.slice(0, -1) + '},'
  113. }
  114. if (hasProps) {
  115. data += props.slice(0, -1) + '},'
  116. }
  117. if (hasEvents) {
  118. data += genEvents(events)
  119. }
  120. return data.replace(/,$/, '') + '}'
  121. }
  122. function genChildren (el) {
  123. if (!el.children.length) {
  124. return 'undefined'
  125. }
  126. return '[' + el.children.map(genNode).join(',') + ']'
  127. }
  128. function genNode (node) {
  129. if (node.tag) {
  130. return genElement(node)
  131. } else {
  132. return genText(node)
  133. }
  134. }
  135. function genText (text) {
  136. if (text === ' ') {
  137. return '" "'
  138. } else {
  139. const exp = parseText(text)
  140. if (exp) {
  141. return 'String(' + exp + ')'
  142. } else {
  143. return JSON.stringify(text)
  144. }
  145. }
  146. }