mh-two-thousand-and-two
2024-04-12 7fc6dbf547b8899d949b67cdec36b96a7d1701c7
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
const compiler = require('@dcloudio/uni-mp-weixin/lib/uni.compiler.js')
const path = require('path')
const t = require('@babel/types')
const crypto = require('crypto')
 
function generateJsCode (properties = '{}') {
  return `
wx.createComponent({
    generic:true,
    props: ${properties},
    render: function(){}
})
`
}
 
function generateCssCode (filename) {
  return `
@import "./${filename}"
`
}
 
function getBaseName (ownerName, parentName, slotName, resourcePath) {
  const str = `${resourcePath}/${parentName}/${slotName}`
  const md5 = crypto.createHash('md5').update(str).digest('hex')
  if (process.env.NODE_ENV !== 'development') {
    return `m${md5.substring(0, 8)}`
  }
  return `${ownerName}--${parentName}--${slotName}--${md5.substring(0, 4)}`
}
 
function hasOwn (obj, key) {
  return Object.prototype.hasOwnProperty.call(obj, key)
}
 
module.exports = Object.assign({}, compiler, {
  directive: 'tt:',
  resolveScopedSlots (slotName, {
    genCode,
    generate,
    ownerName,
    parentName,
    parentNode,
    resourcePath,
    paramExprNode,
    returnExprNodes,
    traverseExpr
  }, state) {
    if (!state.scopedSlots) {
      state.scopedSlots = {}
    }
    const baseName = getBaseName(ownerName, parentName, slotName, resourcePath)
    let componentName = baseName
    if (!hasOwn(state.scopedSlots, baseName)) {
      state.scopedSlots[baseName] = 0
    }
    if (state.scopedSlots[baseName]) {
      componentName = baseName + state.scopedSlots[baseName]
    }
    state.scopedSlots[baseName]++
    // parentNode.attr['generic:scoped-slots-' + slotName] = componentName
    if (!parentNode.attr.generic) {
      parentNode.attr.generic = {}
    }
    parentNode.attr.generic[slotName] = componentName
 
    // 生成 scopedSlots 文件,包括 json,js,wxml,wxss,还需要更新 owner 的 usingComponents
    if (!state.files) {
      state.files = {}
    }
    const extname = path.extname(resourcePath)
 
    // TODO 需要存储 resourcePath 相关 json
 
    const templateFile = resourcePath.replace(ownerName + extname, componentName + extname)
    const templateContent = generate(traverseExpr(returnExprNodes, state), state)
 
    state.files[templateFile] = templateContent
 
    const jsFile = resourcePath.replace(ownerName + extname, componentName + '.js')
 
    const objectProperties = []
 
    if (t.isObjectPattern(paramExprNode)) {
      paramExprNode.properties.forEach(property => {
        const key = property.key
        const value = property.value
        const valueObjectProperties = [
          t.objectProperty(t.identifier('type'), t.nullLiteral())
        ]
        if (t.isIdentifier(value)) {
          if (value.name !== key.name) {
            state.errors.add(`解构插槽 Prop 时,不支持将${key.name}重命名为${value.name},重命名后会影响性能`)
          }
        } else if (t.isAssignmentPattern(value)) {
          valueObjectProperties.push(t.objectProperty(t.identifier('default'), value.right))
        }
        objectProperties.push(t.objectProperty(key, t.objectExpression(valueObjectProperties)))
      })
    } else {
      state.errors.add(`目前仅支持解构插槽 ${paramExprNode.name},如 v-slot="{ user }"`)
    }
    const jsContent = generateJsCode(genCode(t.objectExpression(objectProperties), true))
    state.files[jsFile] = jsContent
 
    try {
      // TODO 使用 getPlatformExts 在单元测试报错,改从 state.options.platform 判断
      const { getPlatformExts } = require('@dcloudio/uni-cli-shared')
      const styleExtname = getPlatformExts().style
      const styleFile = resourcePath.replace(ownerName + extname, componentName + styleExtname)
      const styleContent = generateCssCode(ownerName + styleExtname)
 
      state.files[styleFile] = styleContent
    } catch (error) { }
 
    // 用于后续修复字节跳动小程序不支持抽象节点导致的问题
    const fixExtname = '.fix'
    const extFile = resourcePath.replace(ownerName + extname, componentName + fixExtname)
    state.files[extFile] = `${resourcePath.replace(ownerName + extname, ownerName)},${parentName},${componentName},scoped-slots-${slotName}`
 
    if (!state.generic) {
      state.generic = []
    }
    // 存储,方便后续生成 json
    state.generic.push(componentName)
 
    return ''
  }
})