npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

go-better-code

v1.1.1

Published

The simplest tool to parse/transform/generate code on ast

Downloads

58

Readme

GOGOCODE

全网最简单易上手,可读性最强的 AST 处理工具!

官网:https://gogocode.io

简介:阿里妈妈出的新工具,给批量修改项目代码减轻了痛苦

Install

    npm install gogocode

快速开始

对于下面的代码

const code = `
  const moment = require('moment');
  var a = 1;
  const b = 2;
  function log (x, y = 'World') {
    console.log('a')
    console.log(a, x, y);
  }
`;

创建一个 AST 实例

const $ = require('gogocode');
const AST = $(code);

  • 小明想将 所有的 a 变量名替换为 c,只需要
$(code).replace('a', 'c')

  • 小明改主意了,只想把 var a = 1 里的变量名改为 c,需要两步:

    • 取变量 a 的定义赋值,
    $(code).find('var a = 1');
    • a 变量名替换为 c,并输出整体代码
    $(code)
      .find('var a = 1')
      .attr('declarations.0.id.name', 'c')
      .root()
      .generate();

这是直接操作AST的方式,有没有更简单的方法呢?有!

$(code).replace(`var a = 1`, `var c = 1`)

replace确实用起来爽,但当你在分析转换代码时遇到replace覆盖不到的场景时,请用GoGoCode提供的其他api来精准操作AST吧!


  • 小明又改主意了,想把所有定义语句的 a 都改成 c,只需要将目标语句改一下写成:
$(code).replace(`var a = $_$`, `var c = $_$`)

看到这里,你应该已经理解 findreplace 的第一参有点类似‘jquery 选择器’,而这里的选择器是你需要查找的代码片段,无论想要匹配多么复杂的代码都可以匹配到,其中 $_$ 通配符可以匹配任意确定代码,代码选择器及通配符详细介绍 看这里


  • 小明想试试将代码里的 var 改为 letrequire 改为 import,他发现用 GoGoCode 真的可以像字符串的 replace 一样简单!
$(code)
.replace('var $_$1 = $_$2', 'let $_$1 = $_$2');
.replace('const $_$1 = require($_$2)', 'import $_$1 from $_$2')

关于如何书写选择器,以及replace详解,请见GoGoCode详细文档


API

获取节点

所有的节点获取操作都会返回一个新的AST实例,实例中可能包含多个AST节点路径,如find()siblings()等,某些api返回的实例只会存在一个AST节点路径,如next()

AST.find(selector, options)

| 入参 | | 说明 | 类型 | 默认值 | | --- | --- | --- | --- | --- | | selector | | 代码选择器,可以是代码也可以将代码中的部分内容挖空替换为通配符 | string | 无 | | options | ignoreSequence | 匹配时是否忽略顺序忽略顺序的情况:{a:$_$}匹配{b:1, a:2}需要严格按照顺序匹配的情况:function($_$, b){} 匹配function(a, b){} | boolean | false | | | parseOptions | 同构造函数的parseOptions | | |

当selector中存在 $_$ 通配符时,返回的AST实例中存在 match 属性,也就是被 $_$ 匹配到的AST节点,按照$_$紧接着的key做聚合 如:$('const a = { key: 1, value: "gogo" }').find('const $_$1 = $_$2')

下图是是 $_$1$_$2 分别匹配到的节点以及对应的输出

.parent(level)

获取某个父节点

| 入参 | 说明 | 类型 | 默认值 | | --- | --- | --- | --- | | level | 自内向外第n层父元素 | number | 0 |

.parents()

获取所有父节

.root()

获取根节点,对于js来说是type为'File'的节点,对于html来说是nodeType为'document'的节点 通常对AST进行操作之后需要获取root元素之后再输出

.siblings()

获取所有兄弟节点

.prev()

获取前一个节点

.prevAll()

获取当前节点之前的同级节点

.next()

获取后一个节点

.nextAll()

获取当前节点之后的同级节点

.each(callback)

以每一个匹配的元素作为上下文来执行一个函数。

| 入参 | 说明 | 类型 | 默认值 | | --- | --- | --- | --- | | callback | 对于每个匹配的元素所要执行的函数执行函数时,会给函数传递当前节点nodeindex | function | 无 |

.eq(index)

获取当前链式操作中第N个AST对象

| 入参 | 说明 | 类型 | 默认值 | | --- | --- | --- | --- | | index | 需要获取的AST对象的位置 | number | 0 |

操作节点

.attr()

获取或修改AST节点的属性,入参可分三种情况:

  1. 返回属性名称对应的节点或属性值

| 入参 | 说明 | 类型 | 默认值 | 举例 | | --- | --- | --- | --- | --- | | attrName | ast节点的属性名称,支持多层属性,通过.连接 | string | 无 | declarationsdeclarations.0.id.name |

  1. 修改属性名称对应的节点或属性值

| 入参 | 说明 | 类型 | 举例 | | --- | --- | --- | --- | | attrName | ast节点的属性名称,支持多层属性,通过.连接 | string | declarations declarations.0.id.name | | attrValue | 将第一个入参获取到的节点或属性修改为该入参 注意:字符串不会被解析为ast节点而是直接替换原有属性 | node string | |

  1. 修改多个属性名称对应的节点或属性值

| 入参 | | 类型 | 默认值 | 举例 | | --- | --- | --- | --- | --- | | attrMap | attrName | string | 无 | declarations declarations.0.id.name | | | attrValue | node | string | 无 | |

AST.attr('init', initNode)

AST.attr({ 
  init: initNode,
  'program.body.0.params.0.name': 'a'
})

AST.attr('program.body.0.params.0.name')

.has(selector, options)

判断是否有某个子节点,返回值为boolean类型 入参同.find()

.clone()

返回由当前节点深度复制的新节点

.replace(selector, replacer)

在当前节点内部用replacer替换selector匹配到的代码,返回当前节点

| 入参 | | 解释 | 类型 | 例 | | --- | --- | --- | --- | --- | | selector | | 代码选择器,可以是代码也可以将代码中的部分内容挖空替换为通配符 | string | var $_$1 = $_$2 | | replacer | | 替换代码,同代码选择器通配符顺序与selector的保持一致也可以是确定的ast节点 | string | node | let $_$1 = $_$2 | | options | ignoreSequence | 匹配时是否忽略顺序 | object | 无 | | | parseOptions | 解析入参 | object | 无 |

AST.replace(`Component`, `module.exports = Magix.View.extend`);

AST.replace(
  `export default function calculateData($_$1){$_$2}`, 
  `function calculateData($_$1){$_$2}`
)

AST.replace(
  `navigateToOutside({url: $_$})`, 
  `jm.attachUrlParams($_$)`, 
  options: { ignoreSequence: true }
)

.replaceBy(replacerAST)

用replacerAST替换当前节点,返回新节点

| 入参 | 类型 | | --- | --- | | replacerAST | AST node string |

.after(ast)

在当前节点后面插入一个同级别的节点,返回当前节点

| 入参 | 类型 | | --- | --- | | ast | AST node string |

.before()

在当前节点前面插入一个同级别的节点,返回当前节点

| 入参 | 类型 | | --- | --- | | ast | AST node string |

.append(attr, ast)

在当前节点内部某个数组属性的末尾插入一个子节点,返回当前节点

| 入参 | 类型 | | --- | --- | | attr | 当前节点的数组属性名称 | | ast | AST node string |

  • 为什么需要传入attr

因为某些节点中多个属性都为数组,如函数,存在入参params和函数体body两个数组子节点,必须通过attr来判断插入节点的位置

AST
.find('function $_$() {}')
.append('params', 'b')
.prepend('body', 'b = b || 1;')

.prepend()

在当前节点内部某个数组属性的首位插入一个子节点,返回当前节点

.empty()

清空当前节点所有子节点,返回当前节点

.remove()

移除当前节点,返回根节点

.generate()

将AST对象输出为代码