The following actual combat article published: “GoGoCode combat” one breath to learn 30 AST code replacement tips


As a programmer, of course, always expect your code to “write once, run everywhere”, but the real experience is often “a modification, filling holes”, relying on behind several versions of want to upgrade, going to refactoring old code is watching very uncomfortable, all need the resolute determination, after all, where he has missed or correction is likely to be disaster, What do we usually do?

Give up don’t do

And it immediately alleviates the pain. But if you insist, read on!

The fragrance and limitation of the native method

For simple requirements, such as an example recently seen in nugget, where the console.log(XXX) code is removed from the project, I’m sure your first thought is to simply select the editor batch text and replace it with an empty string:



With regular expressions, we can still handle a lot of requirements, but does it really cover all cases? Some colleagues really like the carriage return.

console
	.log('aaa')
Copy the code

In this case, with more complex requirements or rigorous scenarios, either we write more complex regular expressions, or we have to hard liver AST operations.

The AST is a little bit complicated

Remove console.log using jscodeshift

export default (fileInfo, api) => {
  const j = api.jscodeshift;

  const root = j(fileInfo.source)

  const callExpressions = root.find(j.CallExpression, {
      callee: {
        type: 'MemberExpression'.object: { type: 'Identifier'.name: 'console',}}}); callExpressions.remove();return root.toSource();
};
Copy the code

You need to be familiar with the AST structure, and you need to look at the resolved node structure to write it out slowly. After a while, it’s no better than a curving regular.

Try to combine it

Once, when I was worried about the major API refactoring of a project, I was preparing for a huge refactoring, but my sister couldn’t stand it. Her project was refactoring earlier than mine, and she not only didn’t do it, but also created a tool GoGoCode, which borrowed the two ideas of jQuery: Use this tool to remove console.log(XXX).

const$=require('gogocode')

/** Deliberately messy code **/
const input = ` console .log(\`a, b,c\`); `

// Key code
const output = $(input).replace('console.log()'.' ').generate()

console.log(output)
Copy the code

The innovation is that you parse the console.log() into an AST node to match the node tree in the source code, so there is no coding problem naturally. The code you enter is the equivalent of the jQuery selector, except this time you select the code node.

More examples

Clearing console.log is too easy. Let me give you another example! We often use enumerated lists like this:

const list = [
  {
    text: "A strategy".value: 1.tips: "Atip"}, {text: "B strategy".value: 2.tips: "Btip"}, {text: "C strategy".value: 3.tips: "Ctip",},];Copy the code

One day, in order to unify the enumerations in our code, we need to change the name of the text attribute to name, and the name of the value attribute to ID. This is difficult to exactly match with the regex, and it is a bit difficult to manipulate the AST tree. In GoGoCode, we just need to replace it with this:

const$=require('gogocode')

const input = 'const list = [{text: "Atip", value: 1, tips: "Atip",}, {text: "Atip", value: 2, tips: "Atip",}, {text: "Atip", value: 2, tips: "Atip",}, {text: "Atip", value: 2, tips: "Atip",}, {text: "Atip", "Ctip", value: 3, tips: "Ctip",},]; // the const text in gogocode will not be const text: Const CFG = {text: ''} '. Const CFG = {text: "} '
  
const output = $(input2).replace(
  '{ text: $_$1, value: $_$2, $$$ }'.'{ name: $_$1, id: $_$2, $$$ }'
).generate();
Copy the code

$_$1 and $_$2 match only valid AST nodes in the code, whereas $$$matches the rest of the nodes, similar to es6… “, this code matches text and value. The corresponding values are given name and ID, and the rest is put back intact. In the second half, I deliberately added some “interference code”. In the past, I replaced text: with name: by the string, which would be accidentally injured, but GoGoCode would not.

Take another example from the community in the previous paragraph

This is an example of how to convert React JSX from Jscodeshift to Jscodeshift. This is an example of how to change a code from React JSX to Jscodeshift:

  • Change the import from @alifd/next to ANTd
  • Change from pre-translation to post-translation
  • Button type: normal -> default, medium -> middle
  • If you have a text parameter in Button, change type=”link”
  • Change danger to warning in Button
import * as React from 'react';
import styles from './index.module.scss';
import { Button } from "@alifd/next";

const Btn = () = > {
  return (
    <div>
      <h2>Before translation</h2>
      <div>
        <Button type="normal">Normal</Button>
        <Button type="primary">Prirmary</Button>
        <Button type="secondary">Secondary</Button>
        
        <Button type="normal" text>Normal</Button>
        <Button type="primary" text>Primary</Button>
        <Button type="secondary" text>Secondary</Button>
        
        <Button type="normal" warning>Normal</Button>
      </div>
    </div>
  );
};

export default Btn;
Copy the code

It goes something like this:





This requirement is actually quite common, and the article provides oneImplementation based on Jscodeshift, but if you use theGoGoCodeIt’s a lot more intuitive:

// Omit dependencies and input
const output = $(input)
  .replace(`import { $$$ } from "@alifd/next"`.`import { $$$ } from "antd"`)
  .replace('

'
.'

translated

'
) .replace( `<Button type="normal" $$$></Button>`.`<Button type="default" $$$></Button>` ) .replace( `<Button size="medium" $$$></Button>`.`<Button size="middle" $$$></Button>` ) .replace(`<Button text $$$></Button>`.`<Button type="link" $$$></Button>`) .replace(`<Button warning $$$></Button>`.`<Button danger $$$></Button>`) .generate(); Copy the code

I believe you can know what this code is to do without explaining ~

Open source, hope to get everyone’s feedback

I think this project is very interesting. I can say that I specially made a replace program for the code. My sister said that it was too simple for me. You can follow our account or column, the author will publish a more professional and comprehensive introduction article. The younger sister is Xi Yip from arimom MUX team. Our team has had iconfont, Rap, MockJS and other popular projects in the past. This time we open source GoGoCode to Github: github.com/thx/gogocod… In the hope that the same has a lot of code to modify the needs of friends help. We would like to know what kind of conversion problems you often encounter. If you find it inconvenient to solve or make mistakes with the current GoGoCode, please let us know (issue: github.com/thx/gogocod… QQ group: 735216094). Finally: New project request star support! Github:github.com/thx/gogocod… Liverpoolfc.tv: gogocode. IO