You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
CodeshiftCommunity is a community-owned global registry and documentation hub for codemods. _Think [DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped) for codemods._Providing library maintainers & users with facilities to help write, test, publish and consume codemods in a structured, standardized and familiar way.
7
+
CodeshiftCommunity is a community-owned global registry and documentation hub for codemods. Providing library maintainers & users with facilities to help write, test, publish and consume codemods in a structured, standardized and familiar way.
8
8
9
9
_Inspired by Facebook's [jscodeshift](https://github.com/facebook/jscodeshift)_
You might wonder why we require that codemods are named by a semver version like `react-cool-library/18.0.0`.
45
46
We believe that codemods should aim to target specific package and versions of that package.
46
47
47
48
This is done to:
48
49
49
-
- Make it obvious what the intended purpose of a codemod is
50
+
- Make it obvious what the intended purpose and scope of a codemod is
50
51
- Make it obvious which package is being upgraded
51
52
- Make it easy to play codemods in sequence to allow migration from v4 -> v5 -> v6
52
53
53
54
## Transformers
54
55
55
-
Transformers are the main entry point to your codemod, they are responsible for accepting a raw file and coordinating the appropriate modifications to it.
56
+
Transformers are the main entrypoint to your codemod, they are responsible for accepting a raw file and applying the appropriate modifications to it.
A motion (aka migration) is what we call specific actions performed within a codemod. For example, `updateBorderWidth` or `removeDeprecatedProps`.
80
-
They can be simply thought of a functions that are responsible for a single action within a codemod. This is not required but can help to isolate more complicated parts of your codemod into a single place.
81
+
They can be simply thought of a functions that are responsible for a single action within a codemod. It is not required but they are a helpful design pattern to isolate more complicated parts of your codemod into discrete pieces.
81
82
82
-
Example:
83
+
**Example:**
83
84
84
85
```ts
85
86
function removeDeprecatedProps(
@@ -94,9 +95,9 @@ function removeDeprecatedProps(
94
95
95
96
It's very likely that consumers will run into all sorts of edge-cases when running your transform. That's why it's important to start by writing some tests to assert it's behavior. Luckily, [jscodeshift provides some testing utilities](https://github.com/facebook/jscodeshift#unit-testing).
96
97
97
-
When creating a codemod, it's best to always try to write your tests first. Think about the start and end state and how you might be able to achieve that. Also, make sure to consider as many edge-cases as you possibly can.
98
+
When creating a codemod, it's best to always try to write your tests first (TDD style). Think about the start and end state and how you might be able to achieve that. Also, make sure to consider as many edge-cases as you possibly can.
Copy file name to clipboardExpand all lines: website/docs/contribution.mdx
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,7 +4,7 @@ title: Contribution
4
4
slug: /contribution
5
5
---
6
6
7
-
CodemodCommunity only works because of contributions by users like you!
7
+
CodemodCommunity only works because of contributions by people like you!
8
8
9
9
All forms of contribution are welcome, from [issue reports](https://github.com/CodeshiftCommunity/CodeshiftCommunity/issues/new/choose) to PRs and documentation.
> Code that is written with the sole intent of transforming other code. An example would be a piece of code that takes a normal function, and rewrites it to be an arrow function.
A motion (aka migration) is what we call specific actions performed within a codemod. Put simply, javascript functions that are responsible for a single action within a codemod.
16
+
17
+
For more information see: [Authoring](/docs/authoring#motions)
18
+
19
+
## AST
20
+
21
+
> An abstract syntax tree (AST), is a tree representation of the abstract syntactic structure of source code written in a programming language. Each node of the tree denotes a construct occurring in the source code.
[jscodeshift](https://github.com/facebook/jscodeshift) is the underlying library used by CodeshiftCommunity.
28
+
29
+
## recast
30
+
31
+
[recast](https://github.com/benjamn/recast) is the underlying library used by jscodeshift to parse, transform and output files as ASTs. It's a comparable library to [babel](https://babeljs.io/)
32
+
33
+
> A fantastic library (authored by Ben Newman) that takes an AST and transforms it back into source code. The beauty of recast is that it tries to preserve as much of your codes existing formatting as possible.
> Another great library authored by Ben Newman. It exposes 2 kinds of helpers that you’ll be using: functions that allow you to verify assumptions about nodes, and functions that allow you to compose new nodes to be added to an existing AST.
> The representation of a single construct within an AST. An example of a node could be a node for a `FunctionExpression`. A node will often have many other nodes nested within it.
For more information see the [jscodeshift docs](https://github.com/facebook/jscodeshift#path-objects)
58
+
59
+
## Collection
60
+
61
+
> A group of path objects that exposes helpers to transform all contained paths, or traverse them further. Collections are very similar to the object returned from jQuery’s \$() function.
Copy file name to clipboardExpand all lines: website/docs/guides/prompting-for-human-input.mdx
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -10,7 +10,7 @@ In these scenarios, it's usually the best to migrate as much as you can and bail
10
10
11
11
Or in other words: **"Insert a comment"**.
12
12
13
-
Inserting comments as Codemod output is a completely valid thing to do and highlights to maintainers that they need to manually complete the migration.
13
+
Inserting comments as codemod output is a completely valid thing to do and highlights to maintainers that they need to manually complete the migration.
14
14
When leaving comments, it's helpful to be as descriptive as possible, including all or as much of the context required for the maintainer.
15
15
16
16
Comments are also helpful because when a PR is raised, these prompts can easily be seen in the diff and actioned at the maintainers discression. The key is to make the surface area of your codemod known and let maintainers know where they're needed.
Copy file name to clipboardExpand all lines: website/docs/guides/understanding-asts.mdx
+102Lines changed: 102 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -3,3 +3,105 @@ id: understanding-asts
3
3
title: Understanding ASTs
4
4
slug: /understanding-asts
5
5
---
6
+
7
+
Before writing your first codemod, it’s important to first have a good conceptual understanding of ASTs and how to work with them.
8
+
9
+
## Abstract Syntax Tree (aka AST)
10
+
11
+
> An abstract syntax tree (AST), is a tree representation of the abstract syntactic structure of source code written in a programming language. Each node of the tree denotes a construct occurring in the source code.
Abstract Syntax Trees can be thought of as simply the object representation of your code after being parsed.
16
+
You might already be familiar with the tools and libraries that do this, for example [babeljs](https://babeljs.io/), [recast](https://github.com/benjamn/recast), [eslint](https://eslint.org/) etc.
17
+
These tools parse files into ASTs in preperaton for some work, which generally consists of breaking a raw file down into "Nodes" which are then organized and categorized into a hierarchial format that can be reasoned about, manipulated and output back into a file.
Not all ASTs are the same, different libraries like babel and recast structure their ASTs differently, but if you're comfortable with one it's not too hard to wrap your head around another.
24
+
25
+
For instance, consider this snippet:
26
+
27
+
```jsx
28
+
console.log('Hello, World');
29
+
```
30
+
31
+
The way you might catagorise the anatomy of this expression in your mind is probably not too dissimilar to how it's actually done in [recast](https://github.com/benjamn/recast) (which is what is used in this project).
32
+
So now compare it to the actual resulting AST, generated by recast.
33
+
34
+
```js
35
+
constAST= {
36
+
type:'File',
37
+
program: {
38
+
type:'Program',
39
+
sourceType:'module',
40
+
body: [
41
+
{
42
+
type:'ExpressionStatement',
43
+
expression: {
44
+
type:'CallExpression',
45
+
callee: {
46
+
type:'MemberExpression',
47
+
object: {
48
+
type:'Identifier',
49
+
name:'console',
50
+
},
51
+
computed:false,
52
+
property: {
53
+
type:'Identifier',
54
+
name:'log',
55
+
},
56
+
},
57
+
arguments: [
58
+
{
59
+
type:'StringLiteral',
60
+
extra: {
61
+
rawValue:'Hello, World',
62
+
raw:"'Hello, World'",
63
+
},
64
+
value:'Hello, World',
65
+
},
66
+
],
67
+
},
68
+
},
69
+
],
70
+
},
71
+
};
72
+
```
73
+
74
+
Now your initial reaction might be "wow that's a lot for a simple console.log" and that's a totally fair assessment. But look a little closer and you should start to see some order among the chaos.
75
+
Every [Node](/docs/glossary#node) in this tree is given a "type", these types are key to how you navigate and interact with this object.
76
+
77
+
So for example, if you want to know the arguments this method contains, you could first look at the `arguments` property on the `ExpressionStatement`.
78
+
Arguments in functions can be conceptually thought of as arrays, so it's no surprise that we're presented with an array here.
79
+
Now we can see that in our array we have one element, which is of the type `StringLiteral` and has it's own meta data attached to it containing the value we're looking for: `Hello, World` – Hooray 🎉.
80
+
81
+
Great but where do we go from here? Well it totally depends on what you're trying to achieve.
82
+
If you want to replace the message that's logged, all you'd have to do is replace the `StringLiteral` node with one containing the appropriate message.
83
+
If you want to pass an additional argument to the method, you could simply push a new node into the arguments array and so on.
84
+
85
+
The point is, with this abstract data structure we can inspect and manipulate it into any shape we want! A perfect tool for us codemoders!
86
+
87
+
## AST Explorer
88
+
89
+
ASTs, like in the example above, can get quite large, so you could imagine how big one for a typical javascript source file could get 😱!
90
+
How can one make sense of it all? Well luckily there are indispensable tools out there to help...
91
+
92
+
[astexplorer.net](https://astexplorer.net/) is one of those tools.
93
+
94
+

95
+
96
+
It provides a real-time representation of your code as an AST which is inspectable and lets you write and test transforms against it live in the browser.
97
+
It also supports other ASTs like babel, typescript etc. so for our usecase we'll need to configure it a bit to support recast + jscodeshift.
98
+
99
+
To configure it, follow these steps:
100
+
101
+
1. Set language to Javascript
102
+
2. Set the transformer to `recast`
103
+
3. If you want to enable typescript support, click the little cog icon and set the parser to `TypeScript`
104
+
4. And finally turn the "transform" toggle on, this should show some new panels to write and test your transforms.
105
+
106
+
And there you go, you're all setup with a sandbox to help you test/learn/experiment with!
107
+
From here you should have enough of a grasp of ASTs to try your hand at [writing your first codemod](/docs/your-first-codemod).
Copy file name to clipboardExpand all lines: website/docs/guides/when-not-to-codemod.mdx
+12-6Lines changed: 12 additions & 6 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -39,15 +39,21 @@ For example, consider moving from React class components to a hooks based functi
39
39
40
40
For example: When you need the full runtime result of a React tree
41
41
42
-
### Sometimes we need to know what values are being used.
42
+
### Indirection
43
43
44
-
This can be hard if it is coming in across module boundaries, using object spreading and so on.
44
+
Indirection is one of the biggest hurdles codemods have to overcome.
45
+
Anytime we run into indirection, it is harder to statically analyse how a piece of code is being used and have to take different approaches to work around it.
45
46
46
-
Consider removing `DEPRECATED_BAZ` from `my-module` when it's imported and used like so:
47
+
Indirection as several forms and can include working across module boundaries, using object spreading, dependency injection and so on. Keep an eye out for these cases.
48
+
49
+
For example, consider removing `DEPRECATED_BAZ` from `my-module` when it's imported and used like so:
47
50
48
51
```jsx
49
52
// src/utils/my-module.js
50
-
export { * asmyModule } from'my-module';
53
+
export {
54
+
DEPRECATED_BAZ: 'DEPRECATED_BAZ',
55
+
foo: () => 'hello',
56
+
};
51
57
```
52
58
53
59
```js
@@ -60,7 +66,7 @@ const App = props => {
60
66
};
61
67
```
62
68
63
-
In this case, we're not able to guarantee that you'll be able to safely remove all usages of the `DEPRECATED_BAZ` function.
69
+
In this case, because we're using "rest" in our import statement and then "spreading" it onto our component, we're not able to guarantee that you'll be able to safely remove all usages of the `DEPRECATED_BAZ` function.
64
70
65
71
### Usage paradigm shifts where the old paradigm does not have a 1:1 in the new paradigm
66
72
@@ -112,7 +118,7 @@ const App = props => {
112
118
113
119
For more information on how to write a transform that does this, please refer to the [prompting for human input guide](/docs/prompting-for-human-input).
114
120
115
-
### Thinking outside of the box
121
+
### Aliasing
116
122
117
123
You might come across the case where an "ideal" solution is too complex or too full of edge cases to do reasonably. When this happens, consider looking for a less than ideal but working solution.
0 commit comments