util.js 6.7 KB
Newer Older
fxy060608's avatar
fxy060608 已提交
1 2 3 4 5 6 7 8
const t = require('@babel/types')
const babelTraverse = require('@babel/traverse').default
const babelGenerate = require('@babel/generator').default

const {
  METHOD_RENDER_LIST
} = require('./constants')

fxy060608's avatar
fxy060608 已提交
9
function cached (fn) {
fxy060608's avatar
fxy060608 已提交
10
  const cache = Object.create(null)
fxy060608's avatar
fxy060608 已提交
11
  return function cachedFn (str) {
fxy060608's avatar
fxy060608 已提交
12 13 14 15 16 17 18 19 20 21 22 23
    const hit = cache[str]
    return hit || (cache[str] = fn(str))
  }
}
const customizeRE = /:/g
const camelizeRE = /-(\w)/g
const hyphenateRE = /\B([A-Z])/g

const camelize = cached((str) => {
  return str.replace(camelizeRE, (_, c) => c ? c.toUpperCase() : '')
})

fxy060608's avatar
fxy060608 已提交
24
function getCode (node) {
fxy060608's avatar
fxy060608 已提交
25 26 27 28 29 30 31 32 33
  return babelGenerate(t.cloneDeep(node), {
    compact: true,
    jsescOption: {
      quotes: 'single',
      minimal: true
    }
  }).code
}

fxy060608's avatar
fxy060608 已提交
34
function traverseKey (ast, state) {
fxy060608's avatar
fxy060608 已提交
35 36 37
  let forKey = false
  babelTraverse(ast, {
    noScope: true,
fxy060608's avatar
fxy060608 已提交
38
    ObjectProperty (path) {
fxy060608's avatar
fxy060608 已提交
39 40 41 42 43 44 45 46
      if (forKey) {
        return
      }
      if (path.node.key.name === 'key') {
        forKey = path.node.value
        path.stop()
      }
    },
fxy060608's avatar
fxy060608 已提交
47
    CallExpression (path) {
fxy060608's avatar
fxy060608 已提交
48 49 50 51 52 53 54 55
      if (path.node.callee.name === METHOD_RENDER_LIST) {
        path.stop()
      }
    }
  })
  return forKey
}

fxy060608's avatar
fxy060608 已提交
56
function traverseFilter (ast, state) {
57 58 59 60 61 62 63
  const filterModules = state.options.filterModules
  if (!filterModules.length) {
    return false
  }
  let isFilter = false
  babelTraverse(ast, {
    noScope: true,
fxy060608's avatar
fxy060608 已提交
64
    Identifier (path) {
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
      if (filterModules.includes(path.node.name)) {
        const parentNode = path.parent
        if ( // t.msg || t['msg']
          t.isMemberExpression(parentNode) &&
          parentNode.object === path.node &&
          (
            t.isIdentifier(parentNode.property) ||
            t.isLiteral(parentNode.property)
          )
        ) {
          isFilter = true
          path.stop()
        }
      }
    }
  })
  return isFilter
}

fxy060608's avatar
fxy060608 已提交
84
function wrapper (code, reverse = false) {
fxy060608's avatar
fxy060608 已提交
85 86 87
  return reverse ? `{{!(${code})}}` : `{{${code}}}`
}

fxy060608's avatar
fxy060608 已提交
88
function genCode (node, noWrapper = false, reverse = false, quotes = true) {
fxy060608's avatar
fxy060608 已提交
89 90 91 92 93 94 95 96 97 98 99 100
  if (t.isStringLiteral(node)) {
    return reverse ? `!(${node.value})` : node.value
  } else if (t.isIdentifier(node)) {
    return noWrapper ? node.name : wrapper(node.name, reverse)
  }
  let code = getCode(node)
  if (quotes) {
    code = code.replace(/"/g, '\'')
  }
  return noWrapper ? code : wrapper(code, reverse)
}

fxy060608's avatar
fxy060608 已提交
101
function getForIndexIdentifier (id) {
fxy060608's avatar
fxy060608 已提交
102 103 104
  return `__i${id}__`
}

fxy060608's avatar
fxy060608 已提交
105
function getForKey (forKey, forIndex, state) {
fxy060608's avatar
fxy060608 已提交
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
  if (forKey) {
    if (t.isIdentifier(forKey)) {
      if (forIndex !== forKey.name) { // 非 forIndex
        return '*this'
      } else {
        // TODO
        // state.tips.add(`非 h5 平台 v-for 循环不支持使用索引值 ${forIndex} 作为 key,详情参考:https://uniapp.dcloud.io/use?id=key`)
        return forKey.name
      }
    } else if (t.isMemberExpression(forKey)) {
      return forKey.property.name || forKey.property.value
    } else {
      state.tips.add(`非 h5 平台 :key 不支持表达式 ${getCode(forKey)},详情参考:https://uniapp.dcloud.io/use?id=key`)
    }
  }
  return ''
}

fxy060608's avatar
fxy060608 已提交
124
function processMemberProperty (node, state) {
fxy060608's avatar
fxy060608 已提交
125 126 127 128 129
  if (node.computed) {
    const property = node.property
    if (t.isNumericLiteral(property)) {
      node.property = t.identifier('__$n' + property.value)
    } else if (!t.isStringLiteral(property)) {
fxy060608's avatar
fxy060608 已提交
130
      if (!hasOwn(state.options, '__m__')) {
fxy060608's avatar
fxy060608 已提交
131 132 133 134 135
        state.options.__m__ = 0
        state.options.replaceCodes = {}
      }
      const identifier = '__$m' + (state.options.__m__++) + '__'
      state.options.replaceCodes[identifier] = `'+${genCode(property, true)}+'`
fxy060608's avatar
fxy060608 已提交
136 137 138
      if (state.computedProperty) {
        state.computedProperty[identifier] = property
      }
fxy060608's avatar
fxy060608 已提交
139 140 141 142 143 144
      node.property = t.identifier(identifier)
    }
    node.computed = false
  }
}

fxy060608's avatar
fxy060608 已提交
145
function processMemberExpression (element, state) {
fxy060608's avatar
fxy060608 已提交
146 147 148 149 150 151 152 153 154 155 156 157
  // item['order']=>item.order
  if (t.isMemberExpression(element)) {
    element = t.cloneDeep(element)
    if (t.isStringLiteral(element.property)) {
      element.computed = false
    }
    // item[itemIndex[0]] = item[__$0__]
    // item[1]=item['1']
    processMemberProperty(element, state)

    babelTraverse(element, {
      noScope: true,
fxy060608's avatar
fxy060608 已提交
158
      MemberExpression (path) {
fxy060608's avatar
fxy060608 已提交
159 160 161 162 163 164
        processMemberProperty(path.node, state)
      }
    })

    babelTraverse(element, {
      noScope: true,
fxy060608's avatar
fxy060608 已提交
165
      MemberExpression (path) {
fxy060608's avatar
fxy060608 已提交
166 167 168 169
        if (t.isStringLiteral(path.node.property)) {
          path.node.computed = false
        }
      },
fxy060608's avatar
fxy060608 已提交
170
      StringLiteral (path) {
fxy060608's avatar
fxy060608 已提交
171 172 173 174 175
        path.replaceWith(t.identifier(path.node.value))
      }
    })
  }
  return element
176
}
fxy060608's avatar
fxy060608 已提交
177

fxy060608's avatar
fxy060608 已提交
178
function hasOwn (obj, key) {
fxy060608's avatar
fxy060608 已提交
179
  return Object.prototype.hasOwnProperty.call(obj, key)
fxy060608's avatar
fxy060608 已提交
180 181
}

fxy060608's avatar
fxy060608 已提交
182
const tags = require('@dcloudio/uni-cli-shared/lib/tags')
fxy060608's avatar
fxy060608 已提交
183 184 185 186 187

const {
  getTagName
} = require('./h5')

fxy060608's avatar
fxy060608 已提交
188
function isComponent (tagName) {
fxy060608's avatar
fxy060608 已提交
189 190
  if (
    tagName === 'block' ||
fxy060608's avatar
fxy060608 已提交
191
    tagName === 'component' ||
fxy060608's avatar
fxy060608 已提交
192 193 194
    tagName === 'template' ||
    tagName === 'keep-alive'
  ) {
fxy060608's avatar
fxy060608 已提交
195
    return false
fxy060608's avatar
fxy060608 已提交
196
  }
197 198 199 200 201 202
  // mp-weixin 底层支持 page-meta,navigation-bar
  if (process.env.UNI_PLATFORM === 'mp-weixin') {
    if (tagName === 'page-meta' || tagName === 'navigation-bar') {
      return false
    }
  }
fxy060608's avatar
fxy060608 已提交
203
  return !hasOwn(tags, getTagName(tagName.replace('v-uni-', '')))
fxy060608's avatar
fxy060608 已提交
204 205
}

fxy060608's avatar
fxy060608 已提交
206
function makeMap (str, expectsLowerCase) {
fxy060608's avatar
fxy060608 已提交
207 208 209 210 211
  const map = Object.create(null)
  const list = str.split(',')
  for (let i = 0; i < list.length; i++) {
    map[list[i]] = true
  }
fxy060608's avatar
fxy060608 已提交
212 213 214
  return expectsLowerCase
    ? val => map[val.toLowerCase()]
    : val => map[val]
fxy060608's avatar
fxy060608 已提交
215
}
216 217 218 219 220 221 222 223 224

/**
 * 微信、QQ小程序模板支持的简单类型
 * @param {*} node
 */
function isSimpleObjectExpression (node) {
  return t.isObjectExpression(node) && !node.properties.find(({ key, value }) => !t.isIdentifier(key) || !(t.isIdentifier(value) || t.isStringLiteral(value) || t.isBooleanLiteral(value) || t.isNumericLiteral(value) || t.isNullLiteral(value)))
}

fxy060608's avatar
fxy060608 已提交
225
module.exports = {
fxy060608's avatar
fxy060608 已提交
226
  hasOwn,
fxy060608's avatar
fxy060608 已提交
227 228 229 230
  isUnaryTag: makeMap(
    'image,area,base,br,col,embed,frame,hr,img,input,isindex,keygen,' +
    'link,meta,param,source,track,wbr'
  ),
fxy060608's avatar
fxy060608 已提交
231
  isComponent,
fxy060608's avatar
fxy060608 已提交
232 233 234 235 236 237 238 239 240 241 242 243 244 245
  genCode,
  getCode,
  camelize,
  customize: cached((str) => {
    return camelize(str.replace(customizeRE, '-'))
  }),
  capitalize: cached(str => {
    return str.charAt(0).toUpperCase() + str.slice(1)
  }),
  hyphenate: cached((str) => {
    return str.replace(hyphenateRE, '-$1').toLowerCase()
  }),
  getForKey,
  traverseKey,
246
  traverseFilter,
fxy060608's avatar
fxy060608 已提交
247 248 249 250 251 252 253
  getComponentName: cached((str) => {
    if (str.indexOf('wx-') === 0) {
      return str.replace('wx-', 'weixin-')
    }
    return str
  }),
  processMemberExpression,
254 255 256
  getForIndexIdentifier,
  isSimpleObjectExpression
}