使用ast完成antd4的升级(一)

antd4发布也有一段时间了,也是时候来一波升级了。
antd v4版本对多个组件做了性能优化,日期选择也做了优化调整,icon移出到了单独的库中。
看了升级文档,主要是icon和form2大组件改动较大,官方也提供了升级工具,不过我并没有去尝试使用,根据经验,这类工具坑较多,公司项目也做了其他封装,所有不考虑官方升级工具。
由于对ast有一定的了解和使用,对于这次升级是一个非常合适的方案,有大量的文件需要批量修改。
ast工具主要使用babel,支持tsx,还是比较方便的,先贴下代码。

let newCode = convertCodeUseAst(code, {
  Program(rootPath) {
    rootPath.traverse({
      JSXOpeningElement(path1) {
        let newTagName = null, attributes = []
        let node1 = path1.node
        if (node1.name) {
          let tagName = node1.name.name
          if (tagName == 'Icon') {
            attributes = [...node1.attributes]
            if (attributes) {
              let typeValue
              let themeValue
              path1.traverse({
                JSXAttribute(path2) {
                  let node2 = path2.node
                  if (node2.name.name == 'type') {
                    if (node2.value.type == 'StringLiteral') {
                      typeValue = node2.value.value
                        path2.remove()
                    }
                  }
                  if (node2.name.name == 'theme') {
                    themeValue = node2.value.value
                    path2.remove()
                  }
                }
              })
              if (typeValue == null) {
                return
              }
              let typeValue1 = typeValue
                .replace(/^\w/, (w) => w.toUpperCase())
                .replace(/-\w/g, (w) => w.toUpperCase())
                .replace(/-/g, '')

              let theme = 'Outlined'
              if (themeValue == 'filled') {
                theme = 'Filled'
              }
              if (themeValue == 'twoTone') {
                theme = 'TwoTone'
              }
              newTagName = typeValue1 + theme

              if (iconTypeList.indexOf(newTagName) == -1) {
                iconTypeList.push(newTagName)
              }
              converted = true
            }
          }
        }
        if (newTagName) {
          let attributes1 = attributes.filter(attr => {
            let name = attr.name.name
            return name != 'type' && name != 'theme'
          })

          path1.replaceWith(
            t.jsxOpeningElement(t.jsxIdentifier(newTagName), attributes1, node1.selfClosing)
          )
        }
      }
    })
    for (let iconType of iconTypeList) {
      let isImported = isModuleImported(rootPath, iconType)
      if (!isImported) {
        addImportItem(rootPath, `\nimport {${iconType}} from '@ant-design/icons'`)
      }
    }
  }
}, filePath)

代码仅供参考,这段代码主要用于将icon转化到@ant-design/icon。
思路是先遍历jsx标签,找到Icon标签,然后找到type属性和theme属性,进行对应的转化到antd v4方式。

~下次单独写一遍关于babel进行代码遍历和替换的文章~~

你可能感兴趣的:(antd,ast,react.js)