GOGOCODE初探

833 阅读2分钟

背景

现在前端编写代码都是每次编写,多处运行。但我们在写代码的过程中都是一处编写,百处填坑。或者依赖了大量插件,插件升级、老代码随之打算重构,都需要下很大力度去执行。我们一般都是去硬执行但随之带来了很多问题。比如AST的局限性、AST的复杂性

简介

全网最简单易上手,可读性最强的 AST 处理工具!它主要有以下特点

  • 大幅减少代码量——如果你需要使用AST对代码进行升级、改造、分析,快用gogoAST帮你摆脱繁琐冗余的的代码,专注于你的核心逻辑。不需要traverse,像剥洋葱一样一层一层的对比、操作、构造ast节点。
  • 降低理解成本——甚至不需要理解什么是CallExpression、Identifier、ImportDeclaration这些概念,就可以畅快运用AST。
  • 基于recast,转换后的代码基本与源代码的格式差异最小。
  • 凡是需要借助babel、recast、jscodeshift、esprima...完成的需求,gogoast都能帮你更快更简单的完成。

API

  1. 创建实例
const GG = require('gogoast');
const AST = GG.createAstObj(p, options);  
  1. 通过选择器查找AST节点:getAstsBySelector
const { nodePathList, matchWildCardList } = AST.getAstsBySelector([
    '$_$.setTip($_$, $_$)',
    'tip.show($_$)'
]);
  • 选择器是一段包含通配符(_)的代码
  • nodePathList:返回找到的ast节点路径,包含自己节点、父节点等信息
  • matchWildCardList:返回通配符_代表的节点信息,其中structure是节点完整信息,value是简略信息
  1. 通过选择器替换另一个选择器查找到的AST节点:replaceSelBySel
AST.replaceSelBySel('const $_$ = require($_$)', 'import $_$ from $_$');
AST.replaceSelBySel('$.extend(true, $_$, $_$)', 'Object.assign($_$, $_$)');
AST.replaceSelBySel('$.each($_$, function($_$, $_$) { $_$ } )', '$_$.forEach($_$, $_$)');
  1. 创建一个AST节点:buildAstByAstStr
const type = 'error';
const content = ASTNODE; // 从其他代码中提取出来或者自己构造的ast节点
GG.buildAstByAstStr(`
    Alert.show({
        type: '${type}',
        content: '$_$content$_$'
    })
`, {
    content
})
  1. GG模块其他基本方法
  • 将AST节点转成字符串 generate(ast)
  • 获取AST节点的所有父节点 getParentListByAst(path)
  • 判断一个AST节点是否包含某子节点,子节点用选择器表示 hasChildrenSelector(path, childSelector)
  • 用一个AST节点替换某个字符串 replaceStrByAst
  • replaceAstByAst
  • getPrevAst
  • getNextAst
  • insertAstListBefore
  • insertAstListAfter
  • removeAst
  1. 特殊类型AST节点的构造方法
  • buildObjectProperty
AST.buildObjectProperty({
    url: 'getList',
    type: 'get'
})
  • appendJsxAttr
const locaid = '98s8dh3';
const params = [ 'a=${aa}', 'b=${{aaa:"222",xxx:{ssss:111}}}', 'c=${"s"}', 'd=${a+1}','e=${ ss?2:1}' ]

AST.appendJsxAttr({
   'attr1: `{${'`'}gostr='$'{gostr};locaid=d${locaid};${params.join('&')}}${'`'}}`, // 模板字符串
    a: `{a+1}`, // 表达式
    b: `'a'`, // 字符串
    c: `{a}` // 变量
});

// 结果:
<div attr1={`gostr=${gostr};locaid=d98s8dh3;a=${aa}&b=${{aaa:"222",xxx{ssss:111}}}&c=${"s"}&d=${a+1}&e=${ ss?2:1}}`}a={a+1} b='a' c={a}>
</div>

试例

js代码

import a from 'a';
console.log('get A')
var b = console.log()
console.log.bind()
var c = console.log
console.log = func

使用gogocode实现

const AST = GG.createAstObj(code);
AST.replaceSelBySel(`var $_$ = console.log()`, `$_$ = void 0`);
AST.replaceSelBySel(`console.log()`, null);
AST.replaceSelBySel(`var $_$ = console.log`, `$_$ = function(){}`);
const result = AST.generate();

相比自定义babel插件简化三分之一的代码,代码结构上也让人更好理解。