Skip to content

插入Number类型的节点

在第5篇中,已经记录了是如何利用babel系的库实现在源代码中,插入一个Number类型的变量的。与之对应,我们可以继续利用acorn来实现一个同样的需求,加深理解。

在此之前,先理一下插入节点的逻辑:

  1. 利用node的文件读写能力,读取需要操作的文件
  2. 利用acorn.parse将源代码字符串转换为AST对象
  3. 利用@babel/types创建节点
  4. ast.body中顺序添加节点
  5. 利用escodegen将ast转化为源代码字符串
  6. 利用prettier将源代码字符串格式化

我们现在实现的是一个极其简单的新增节点逻辑,所以不存在"先查后增"的操作,只需要顺序添加进入ast对象就可以。

在前面已经介绍过是怎么利用types创建的节点,在我学习使用的过程中,我们会发现一个明显的特效,只要我们的对ast对象的改动是可以被正常解析的正常对象,最后生成的代码就不会有问题。

另外,还记得我们之前辛辛苦苦探索实现的,新增注释节点的例子吗?当时的难点主要是acorn默认不解析BlockCommenetLineComment,需要做一些特殊操作来实现这个新增注释需求。

我是被困了很久,最后才发现了解决这些问题的方法,不知道你们在写自己的测试用例的时候用了多久。

因为types方法中的方法是直接修改的ast对象,所以有一个功能是可以利用这个特性,来一个快捷操作和链式操作,比如下面实现的这个例子:

javascript
import * as acorn from 'acorn'
import fs from 'fs-extra'
import escodegen from 'escodegen'
import { VariableDeclaration, VariableDeclarator, Identifier, addComment } from '@babel/types'

const filepath = './demo.js'

const workflow = async () => {
const source = await fs.readFile(filepath, { encoding: 'utf-8' })

// 利用acorn解析成ast
const ast = await acorn.parse(source, { sourceType: 'module', ecmaVersion: 2021 })

// 生成一个声明表达式节点
const var1 = VariableDeclaration('const', [
VariableDeclarator(Identifier('a_num1'), Identifier('12'))
])

// 这里调用@@babel/types中提供的addComment方法,添加一条块级注释
addComment(var1, 'leading', '这里是由acorn生成的注释', false)

// 直接在文件后追加节点
ast.body.push(var1)

// 利用escodegen提供的generate方法生成源代码
const output = await escodegen.generate(ast, {
comment: true
})

console.log('=========> output', output)
}

workflow()

我们可以将这个acorn版本与babel版本做一个对比,我们可以完全利用@babel/types里面提供的方法去新增节点和添加注释节点。

所不同处,就是最后一步,将ast转换源代码。前面我也记录了为什么不可以利用@babel/coretransformAstFromSync方法去转换由acorn转换的ast对象。转换的工具很多,并不局限于我所使用的两个库,但是转换的套路和逻辑大致上是一样的。

这就是我为什么要用两个不同的库来实现一个相同的需求。很多东西使用的时候互相对比就会发现很多有意思的东西,更容易接触到一些相当偏门的知识点。

源代码地址:

  1. babel版本: https://github.com/stack-wuh/mini-cli/blob/main/core/create-number-node-babel/babel.js
  2. acorn版本: https://github.com/stack-wuh/mini-cli/blob/main/core/create-number-node-babel/acorn.js

MIT License.