const {
|
parseExpression
|
} = require('@babel/parser')
|
const t = require('@babel/types')
|
|
const ID = '_i'
|
const ITERATOR1 = '$1'
|
const ITERATOR2 = '$2'
|
const ITERATOR3 = '$3'
|
const SET_DATA = '_$s'
|
const GET_DATA = '_$g'
|
const SET_MP_CLASS = '_$smc'
|
const GET_CHANGE_DATA = '_$gc' // wxs
|
|
const C_IS = 'is'
|
const C_SLOT_TARGET = 'st'
|
const C_REF = 'ref'
|
const C_NAME = 'name'
|
|
const V_FOR = 'f'
|
const V_IF = 'i'
|
const V_ELSE_IF = 'e'
|
|
// web components
|
const elements = ['uni-view']
|
|
function isVar (str) {
|
if (!str) {
|
return false
|
}
|
const expr = parseExpression(str)
|
if (
|
t.isStringLiteral(expr) ||
|
t.isNumericLiteral(expr) ||
|
t.isBooleanLiteral(expr) ||
|
t.isNullLiteral(expr)
|
) {
|
return false
|
}
|
return true
|
}
|
|
function addRawAttr (el, name, value) {
|
el.attrsMap[name] = value
|
el.attrsList.push({
|
name,
|
value
|
})
|
}
|
|
function updateEleId (el, it, state) {
|
if (el.type !== 1) {
|
return
|
}
|
const newId = getNewId(el.attrsMap[ID], it)
|
addRawAttr(el, ID, newId)
|
if (el.attrs) {
|
const attr = el.attrs.find(attr => attr.name === ID)
|
attr.value = newId
|
}
|
el.children.forEach(child => {
|
if (!child.for) { // 忽略嵌套 for
|
updateEleId(child, it)
|
} else {
|
child.$parentIterator3 = (child.$parentIterator3 ? (child.$parentIterator3 + '+') : '') + it
|
child.forId = `${child.forId}+'-'+${it}`
|
}
|
})
|
el.ifConditions && el.ifConditions.forEach((con, index) => {
|
index !== 0 && updateEleId(con.block, it, state)
|
})
|
el.scopedSlots && Object.values(el.scopedSlots).forEach((slot, index) => {
|
updateEleId(slot, it, state)
|
})
|
}
|
|
function getBindingAttr (el, name) {
|
return getAndRemoveAttr(el, ':' + name) ||
|
getAndRemoveAttr(el, 'v-bind:' + name)
|
}
|
|
function getAndRemoveAttr (el, name) {
|
let val
|
if ((val = el.attrsMap[name]) != null) {
|
const list = el.attrsList
|
for (let i = 0, l = list.length; i < l; i++) {
|
if (list[i].name === name) {
|
list.splice(i, 1)
|
break
|
}
|
}
|
}
|
delete el.attrsMap[name]
|
return val
|
}
|
|
function updateForIterator (el, state) {
|
if (!el.for) {
|
return
|
}
|
// 简单处理,确保所有 for 循环,均包含 1,2,3
|
const forIteratorId = state.forIteratorId++
|
if (!el.iterator1) {
|
el.iterator1 = ITERATOR1 + forIteratorId
|
}
|
if (!el.iterator2) {
|
el.iterator2 = ITERATOR2 + forIteratorId
|
}
|
if (!el.iterator3) {
|
el.iterator3 = ITERATOR3 + forIteratorId
|
}
|
}
|
|
function updateForEleId (el, state) {
|
updateForIterator(el, state)
|
if (el.for) {
|
const it = el.$parentIterator3 ? (el.$parentIterator3 + '+' + "'-'" + '+' + el.iterator3) : el.iterator3
|
updateEleId(el, it, state)
|
}
|
}
|
|
function getNewId (id, it) {
|
return Number.isInteger(id) ? `("${id}-"+${it})` : `(${id}+${it})`
|
}
|
|
function updateScopedSlotEleId (el, state) {
|
// TODO 暂不考虑 scopedSlot 嵌套情况
|
if (el.slotScope) {
|
const getNewId = function (id, it) {
|
return Number.isInteger(id) ? `("${id}-"+${it})` : `(${id}+"-"+${it})`
|
}
|
const updateEleId = function (el) {
|
if (el.type !== 1) {
|
return
|
}
|
const it = '_si'
|
const newId = getNewId(el.attrsMap[ID], it)
|
if (el.forId) {
|
el.forId = getNewId(el.forId, it)
|
}
|
addRawAttr(el, ID, newId)
|
if (el.attrs) {
|
const attr = el.attrs.find(attr => attr.name === ID)
|
attr.value = newId
|
}
|
el.children.forEach(child => {
|
if (!child.slotScope) { // 忽略嵌套 scopedSlot
|
updateEleId(child, state)
|
}
|
})
|
}
|
if (el.tag === 'template' && el.slotTarget) { // new v-slot
|
el.children.forEach(child => {
|
if (!child.slotScope) { // 忽略嵌套 scopedSlot
|
updateEleId(child, state)
|
}
|
})
|
} else { // old slot-scope
|
updateEleId(el)
|
}
|
}
|
}
|
|
function getForEl (el) {
|
if (el.for) {
|
return el
|
}
|
if (el.parent && el.parent.for && (el.parent.tag === 'template' || el.parent.tag === 'block')) {
|
return el.parent
|
}
|
}
|
|
function processForKey (el) {
|
const forEl = getForEl(el)
|
if (forEl && !el.key) { // 占位的 text 标签也无需添加 key
|
if (!isVar(forEl.for)) { // <view v-for="10"></view>
|
return
|
}
|
const it = forEl.iterator3
|
if (forEl.tag === 'template' || forEl.tag === 'block') {
|
if (forEl !== el) {
|
const keyIndex = forEl.children.indexOf(el)
|
el.key = `${forEl.forId}+'-${keyIndex}'+${it}`
|
} else { // 当 template 下只有文本节点
|
if (
|
el.children &&
|
el.children.length &&
|
!el.children.find(child => child.type === 1)
|
) {
|
el.children[0].parent = el
|
if (!el.children.find(child => child.key)) {
|
el.children[0].key = `${forEl.forId}+'-0'+${it}`
|
}
|
return true
|
}
|
}
|
} else {
|
el.key = `${forEl.forId}+'-'+${it}`
|
}
|
}
|
}
|
|
function hasOwn (obj, key) {
|
return hasOwnProperty.call(obj, key)
|
}
|
|
function traverseNode (el, parent, state, isScopedSlot) {
|
state.transformNode(el, parent, state, isScopedSlot)
|
el.children && el.children.forEach((child, index) => {
|
state.childIndex = index
|
traverseNode(child, el, state, isScopedSlot)
|
})
|
el.ifConditions && el.ifConditions.forEach((con, index) => {
|
if (index !== 0) {
|
state.childIndex = index
|
traverseNode(con.block, el, state, isScopedSlot)
|
}
|
})
|
el.scopedSlots && Object.values(el.scopedSlots).forEach((slot, index) => {
|
state.childIndex = index
|
slot.slotScope = `${slot.slotScope}, _svm, _si`
|
if (slot.slotTargetDynamic && slot.slotTarget) {
|
slot.slotTarget = state.createGenVar(slot.attrsMap[ID])(C_SLOT_TARGET, slot.slotTarget)
|
}
|
traverseNode(slot, el, state, true)
|
})
|
}
|
|
function addAttr (el, name, value, dynamic) {
|
const attrs = dynamic
|
? (el.dynamicAttrs || (el.dynamicAttrs = []))
|
: (el.attrs || (el.attrs = []))
|
attrs.push({
|
name,
|
value,
|
dynamic
|
})
|
el.plain = false
|
}
|
|
function removeRawAttr (el, name) {
|
delete el.attrsMap[name]
|
const index = el.attrsList.findIndex(attr => attr.name === name)
|
index !== -1 && el.attrsList.splice(index, 1)
|
}
|
|
function removeRawBindingAttr (el, name) {
|
removeRawAttr(el, ':' + name)
|
removeRawAttr(el, 'v-bind:' + name)
|
}
|
|
function addHandler (el, name, value, important) {
|
const events = el.events || (el.events = {})
|
const handlers = events[name]
|
const newHandler = {
|
value: value.trim(),
|
dynamic: undefined
|
}
|
if (Array.isArray(handlers)) {
|
important ? handlers.unshift(newHandler) : handlers.push(newHandler)
|
} else if (handlers) {
|
events[name] = important ? [newHandler, handlers] : [handlers, newHandler]
|
} else {
|
events[name] = newHandler
|
}
|
el.plain = false
|
}
|
|
module.exports = {
|
C_IS,
|
C_REF,
|
C_NAME,
|
V_FOR,
|
V_IF,
|
V_ELSE_IF,
|
ID,
|
SET_DATA,
|
GET_DATA,
|
SET_MP_CLASS,
|
GET_CHANGE_DATA,
|
elements,
|
isVar,
|
hasOwn,
|
addAttr,
|
addRawAttr,
|
removeRawAttr,
|
removeRawBindingAttr,
|
getNewId,
|
getForEl,
|
addHandler,
|
processForKey,
|
updateForEleId,
|
updateScopedSlotEleId,
|
getBindingAttr,
|
getAndRemoveAttr,
|
traverseNode
|
}
|