| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 |
- import { genEvents, addHandler } from './events'
- import { genModel } from './model'
- import {
- parseText,
- parseModifiers,
- removeModifiers,
- getAndRemoveAttr
- } from './helpers'
- const dirRE = /^v-|^@|^:/
- const bindRE = /^:|^v-bind:/
- const onRE = /^@|^v-on:/
- const mustUsePropsRE = /^(value|selected|checked|muted)$/
- export function generate (ast) {
- const code = ast ? genElement(ast) : '__h__("div")'
- return new Function(`with (this) { return ${code}}`)
- }
- function genElement (el, key) {
- let exp
- if ((exp = getAndRemoveAttr(el, 'v-for'))) {
- return genFor(el, exp)
- } else if ((exp = getAndRemoveAttr(el, 'v-if'))) {
- return genIf(el, exp)
- } else if (el.tag === 'template') {
- return genChildren(el)
- } else {
- return `__h__('${el.tag}', ${genData(el, key)}, ${genChildren(el)})`
- }
- }
- function genIf (el, exp) {
- return `(${exp}) ? ${genElement(el)} : null`
- }
- function genFor (el, exp) {
- const inMatch = exp.match(/([a-zA-Z_][\w]*)\s+(?:in|of)\s+(.*)/)
- if (!inMatch) {
- throw new Error('Invalid v-for expression: ' + exp)
- }
- const alias = inMatch[1].trim()
- exp = inMatch[2].trim()
- let key = getAndRemoveAttr(el, 'track-by')
- if (!key) {
- key = 'undefined'
- } else if (key !== '$index') {
- key = alias + '["' + key + '"]'
- }
- return `(${exp}) && (${exp}).map(function (${alias}, $index) {return ${genElement(el, key)}})`
- }
- function genData (el, key) {
- if (!el.attrs.length) {
- return '{}'
- }
- let data = '{'
- let attrs = 'attrs:{'
- let props = 'props:{'
- let events = {}
- let hasAttrs = false
- let hasProps = false
- let hasEvents = false
- // key
- if (key) {
- data += `key:${key},`
- }
- // class
- const classBinding = getAndRemoveAttr(el, ':class') || getAndRemoveAttr(el, 'v-bind:class')
- if (classBinding) {
- data += `class: ${classBinding},`
- }
- const staticClass = getAndRemoveAttr(el, 'class')
- if (staticClass) {
- data += `staticClass: "${staticClass}",`
- }
- // parent elements my need to add props to children
- if (el.props) {
- hasProps = true
- props += el.props + ','
- }
- // loop attributes
- for (let i = 0, l = el.attrs.length; i < l; i++) {
- let attr = el.attrs[i]
- let name = attr.name
- let value = attr.value
- if (dirRE.test(name)) {
- // modifiers
- const modifiers = parseModifiers(name)
- name = removeModifiers(name)
- if (bindRE.test(name)) {
- name = name.replace(bindRE, '')
- if (name === 'style') {
- data += `style: ${value},`
- } else if (mustUsePropsRE.test(name)) {
- hasProps = true
- props += `"${name}": (${value}),`
- } else {
- hasAttrs = true
- attrs += `"${name}": (${value}),`
- }
- } else if (onRE.test(name)) {
- hasEvents = true
- name = name.replace(onRE, '')
- addHandler(events, name, value, modifiers)
- } else if (name === 'v-model') {
- hasProps = hasEvents = true
- props += genModel(el, events, value, modifiers) + ','
- } else {
- // TODO: normal directives
- }
- } else {
- hasAttrs = true
- attrs += `"${name}": (${JSON.stringify(attr.value)}),`
- }
- }
- if (hasAttrs) {
- data += attrs.slice(0, -1) + '},'
- }
- if (hasProps) {
- data += props.slice(0, -1) + '},'
- }
- if (hasEvents) {
- data += genEvents(events)
- }
- return data.replace(/,$/, '') + '}'
- }
- function genChildren (el) {
- if (!el.children.length) {
- return 'undefined'
- }
- return '[' + el.children.map(genNode).join(',') + ']'
- }
- function genNode (node) {
- if (node.tag) {
- return genElement(node)
- } else {
- return genText(node)
- }
- }
- function genText (text) {
- if (text === ' ') {
- return '" "'
- } else {
- const exp = parseText(text)
- if (exp) {
- return 'String(' + exp + ')'
- } else {
- return JSON.stringify(text)
- }
- }
- }
|