Skip to content

AST:转换箭头函数

这里,我们自己来实现一个Bebel 插件,来转换 箭头函数普通函数

主要是利用 @babel/core 库的 transform 方法,还有 @babel/types 库的 returnStatement, blockStatement, functionExpression

工具介绍

  • @babel/core

    • transform 方法会帮我们自动遍历,在第二个参数中的 plugins 参数,可以使用相应的预设或者插件来转换相应的代码
  • @babel/types

    • returnStatement 声明一个 "return xxx"AST
    • blockStatement 声明一个 "{ xxx }"AST
    • functionExpression 声明一个 "function xxx"AST
  • 在线 AST Explorer 工具

转化对比

TypeScript
const fn = (a, b) => a + b;
TypeScript
const fn = function(a, b) { return a + b }
  • 本文转换前 const fn = (a, b) => a + b;AST 代码
  • 本文转换后 const fn = function(a, b) { return a + b } AST 代码

代码

TypeScript
import { returnStatement, blockStatement, functionExpression } from '@babel/types'
import { transform } from '@babel/core'
import { default as chalk } from 'chalk'
import { log } from '@common/index'

import { PluginItem, NodePath, BabelFileResult } from '@babel/core'
import { ArrowFunctionExpression } from '@babel/types'

const arrowFnPlugin = (): PluginItem => {
  return {
    visitor: {
      // 当访问到某个路径的时候进行匹配
      ArrowFunctionExpression(path: NodePath<ArrowFunctionExpression>) {
        const { node } = path //      节点 node: (a, b) => a + b
        const { params } = node //    函数的参数
        const { body }: any = node // 二进制表达式: a + b

        // * returnStatement: return a + b
        const newReturnStatement = returnStatement(body)

        // * blockStatement: { return a + b }
        const newBlockStatement = blockStatement([newReturnStatement])

        // * functionExpression: function(a, b) { return a + b }
        const newFunctionExpression = functionExpression(null, params, newBlockStatement)

        path.replaceWith(newFunctionExpression)
      },
    },
  }
}

const transformArrowFn = (code = `const fn = (a, b) => a + b;`): string | null | undefined => {
  log(chalk.green('old => '))
  log(code)

  const data: BabelFileResult | null = transform(code, {
    plugins: [arrowFnPlugin()],
  })

  // 转换后 const fn = function(a, b) { return a + b }
  log(chalk.red('new => '))
  log(data?.code)

  return data?.code
}

export default transformArrowFn
export { arrowFnPlugin }