generate.js 4.1 KB
Newer Older
fxy060608's avatar
fxy060608 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
const {
  SELF_CLOSING_TAGS,
  INTERNAL_EVENT_LINK
} = require('../constants')

function processElement (ast, state, isRoot) {
  const platformName = state.options.platform.name
  // <template slot="f"></template>
  if (ast.type === 'template' && ast.attr.hasOwnProperty('slot')) {
    ast.type = 'view'
  }

  if (ast.attr.hasOwnProperty('textContent')) {
    ast.children = [ast.attr['textContent']]
    delete ast.attr['textContent']
  }
  if (ast.attr.hasOwnProperty('innerHTML')) {
    ast.children = [{
      type: 'rich-text',
      attr: {
        nodes: ast.attr['innerHTML']
      },
      children: []
    }]
    delete ast.attr['innerHTML']
  }
  if (state.options.platform.isComponent(ast.type)) {
    if (platformName === 'mp-alipay') {
      ast.attr['onVueInit'] = INTERNAL_EVENT_LINK
    } else if (platformName !== 'mp-baidu') {
      ast.attr['bind:' + INTERNAL_EVENT_LINK] = INTERNAL_EVENT_LINK
    }

    const children = ast.children
    // default slot
    let defaultSlot = false
    const slots = []
    for (let i = children.length - 1; i >= 0; i--) {
      const childElement = children[i]
      // <block name="left"></block> => <view name="left"></view>
      if (typeof childElement !== 'string' && childElement.attr.slot) {
        if (childElement.type === 'block') {
          childElement.type = 'view'
        }
        slots.push(childElement.attr.slot)
      } else {
        defaultSlot = true
      }
    }
    if (defaultSlot) {
      slots.push('default')
    }
    if (ast.attr.generic) {
      Object.keys(ast.attr.generic).forEach(scopedSlotName => {
        slots.push(scopedSlotName)
      })
      delete ast.attr.generic
    }
    if (slots.length && platformName !== 'mp-alipay') { // 标记 slots
      ast.attr['vue-slots'] = '{{[' + slots.reverse().map(slotName => `'${slotName}'`).join(',') + ']}}'
    }
    if (ast.attr['id'] && ast.attr['id'].indexOf('{{') === 0) {
      state.tips.add(`id 作为属性保留名,不允许在自定义组件 ${ast.type} 中定义为 props`)
    }
    if (ast.attr.hasOwnProperty('data')) { // 百度中会出现异常情况
      state.tips.add(`data 作为属性保留名,不允许在自定义组件 ${ast.type} 中定义为 props`)
    }
  }
}

function genElement (ast, state, isRoot = false) {
  if (!ast) {
    return ''
  }
  if (typeof ast === 'string') {
    return genText(ast, state)
  }

  processElement(ast, state, isRoot)

  const names = Object.keys(ast.attr)
  const props = names.length
    ? ' ' +
fxy060608's avatar
fxy060608 已提交
84 85 86 87 88 89 90 91 92 93 94
    names
      .map(name => {
        if (name.includes(':else')) {
          return name
        }
        if (ast.attr[name] === '' && name !== 'value') { // value属性需要保留=''
          return name
        }
        return `${name}="${ast.attr[name]}"`
      })
      .join(' ')
fxy060608's avatar
fxy060608 已提交
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
    : ''
  if (SELF_CLOSING_TAGS.includes(ast.type)) {
    return `<${ast.type}${props}/>`
  }

  let children = ast.children
    .map(child => {
      return genElement(child, state, isRoot && ast.type === 'block') // 如果根节点是 block,则继续 root
    })
    .join('')

  if (ast.scoped) { // 简单处理的 scoped slots 子节点的变量
    children = children.replace(new RegExp(ast.scoped + '.', 'g'), '')
  }
  return `<${ast.type}${props}>${children}</${ast.type}>`
}

function genText (ast, state) {
  return ast
}

116 117 118 119 120 121 122 123 124 125 126 127 128 129
function parsePageMeta (ast, state) {
  // 目前仅 mp-weixin 支持 page-meta
  if (state.options.platform.name === 'mp-weixin') {
    const children = ast.children
    if (Array.isArray(children) && children.find(child => child.type === 'page-meta')) {
      return children
    }
  }
  return ast
}

module.exports = function generate (ast, state) {
  ast = parsePageMeta(ast, state)

fxy060608's avatar
fxy060608 已提交
130 131 132 133 134 135 136 137 138
  if (!Array.isArray(ast)) {
    ast = [ast]
  }

  let code = ast.map(ast => genElement(ast, state, true)).join('')

  const replaceCodes = state.options.replaceCodes
  if (replaceCodes) {
    Object.keys(replaceCodes).forEach(key => {
fxy060608's avatar
fxy060608 已提交
139
      code = code.replace(new RegExp(key.replace('$', '\\$'), 'g'), replaceCodes[key])
fxy060608's avatar
fxy060608 已提交
140 141 142 143 144
    })
  }

  return code
}