Skip to content

Commit df57e58

Browse files
committed
initial authoring doc revamp
1 parent 3ba86dc commit df57e58

File tree

10 files changed

+307
-234
lines changed

10 files changed

+307
-234
lines changed

website/docs/authoring.mdx

Lines changed: 38 additions & 175 deletions
Original file line numberDiff line numberDiff line change
@@ -4,199 +4,62 @@ title: Authoring
44
slug: /authoring
55
---
66

7-
Before writing a codemod, please read the [contribution guide](docs/contribution) 🙏
7+
There are currently three approaches to authoring and publishing a codeshift package.
8+
Which one to use depends on your particular use case.
89

9-
## Initializing
10+
1. [Contribute to the Community Folder](#1-contribute-to-the-community-folder)
11+
1. [Add codeshift to an existing package](#2-add-codeshift-to-an-existing-package)
12+
1. [Create a stand-alone codeshift package](#3-create-a-stand-alone-codeshift-package)
1013

11-
Create a folder structure for your new codemod by running:
14+
## 1. Contribute to the Community Folder
1215

13-
`yarn codeshift:init -p [package-name] -v [version]`
16+
The Community Folder is the public directory of codemods hosted and published directly from this repository, [visible here](https://github.com/CodeshiftCommunity/CodeshiftCommunity/tree/main/community).
17+
This directory can be compared to and treated the same as the Typescript type definition regisistry: [DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped).
1418

15-
For example:
19+
_Please see the [Contribution guide](contribution) for more information._
1620

17-
`yarn init:codemods react-cool-library 10.0.0`
21+
Use this method if you want:
1822

19-
And for scoped packages:
23+
- Your codemods to be open source
24+
- Build tooling, dependency management and project setup to be handled for you
25+
- The community to help maintain and contribute to your codemods
26+
- Documentation to be automatically generated and available on the [Regisistry page](atlaskit__avatar)
2027

21-
`yarn init:codemods @scope/react-cool-library 10.0.0`
28+
Do not use this method if:
2229

23-
It will create a package within the `/community` subdirectory, this is for you to implement your codemod.
30+
- Your codemods target a closed source package/repository
31+
- Your codemods are generic in that they do not target any particular package
32+
- Your codemods should be close sourced or contain sensitive data
2433

25-
## File structure
34+
## 2. Add codeshift to an existing package
2635

27-
The file structure of your codemod will look like this:
36+
For existing npm packages (like react), you have the option to expose codemods directly from the package by simply creating a `codeshift.config.js` at either the root, `/src` or `/codemods` directory.
37+
Given that the config and codemod files are then published and available on NPM, `codeshift-cli` will be able to find and run codemods using the `--package` flag.
2838

29-
```
30-
community/[package-name]/[version]
31-
/codeshift.config.js // main entrypoint containing configuration and references to your transforms
32-
/transform.ts // main logic (should contain a transformer)
33-
/transform.spec.ts // main tests
34-
/motions // different operations that make up the codemod
35-
/[motion-name].ts // motion
36-
/[motion-name].spec.ts // motion tests
37-
```
39+
Use this method if you want:
3840

39-
**Example:**
41+
- To get up and running with an existing package with very little overhead
42+
- Control over where and how your codeshift package is hosted
43+
- Control over tooling, dependencies and techstack
44+
- To remove a previously created jscodeshift cli wrapper and instead use the generic codeshift-cli
4045

41-
```
42-
community/react-cool-library/18.0.0
43-
/codeshift.config.js
44-
/transform.ts
45-
/transform.spec.ts
46-
/motions
47-
/remove-ref-usage.ts
48-
/remove-ref-usage.spec.ts
49-
```
46+
Do not use this method if:
5047

51-
## Configuration
48+
- Your package is close sourced
49+
- You want docs to be automatically generated and available on the [Regisistry page](atlaskit__avatar)
5250

53-
Each codemod package should be coupled with a `codeshift.config.js` file.
54-
The config file is the entry-point of your codemod and is responsible for holding all of the relevant
55-
metadata about it, as well as references to the transformer functions themselves.
51+
## 3. Create a stand-alone codeshift package
5652

57-
They typically look like this:
53+
Codeshift packages can be created as a stand-alone package.
5854

59-
```js
60-
export default {
61-
maintainers: ['danieldelcore'],
62-
transforms: {
63-
'18.0.0': require.resolve('./18.0.0/transform'),
64-
'19.0.0': require.resolve('./19.0.0/transform'),
65-
},
66-
};
67-
```
55+
_Please see the [External Packages guide](external-packages) for more information._
6856

69-
- `maintainers`: Github usernames of the people that maintain that codemod, they will be notified on PRs etc.
70-
- `transforms`: A key value pair of transforms organized by semver-compatible versions
57+
Use this method if you want:
7158

72-
## Versioning
59+
- Control over where and how your codeshift package is hosted
60+
- Control over tooling, dependencies and techstack
61+
- The option to create completely generic codemods that don't target specific packages
7362

74-
You might wonder why we require that codemods are named by a semver version like `react-cool-library/18.0.0`.
75-
We believe that codemods should aim to target specific package and versions of that package.
63+
Do not use this method if:
7664

77-
This is done to:
78-
79-
- Make it obvious what the intended purpose and scope of a codemod is
80-
- Make it obvious which package is being upgraded
81-
- Make it easy to play codemods in sequence to allow migration from v4 -> v5 -> v6
82-
83-
But importantly, in terms of authoring, this also allows us to **retrospectivally patch published codemods**.
84-
Patched codemods will then be automatically published when merged to the repo, ensuring that consumers are always running the latest version.
85-
86-
## Transformers
87-
88-
Transformers are the main entrypoint to your codemod, they are responsible for accepting a raw file, applying the appropriate modifications to it and finally outputting the resulting AST to the original file.
89-
90-
**Example:**
91-
92-
```ts
93-
import { hasImportDeclaration } from '@codeshift/utils';
94-
import updateBorderWidth from './motions/update-border-width';
95-
96-
export default function transformer(file, { jscodeshift: j }, options) {
97-
const source = j(file.source);
98-
99-
if (!hasImportDeclaration(j, source, 'my')) {
100-
return file.source; // Writes original untouched file
101-
}
102-
103-
// Checks if the file needs to be modified
104-
updateBorderWidth(j, source); // Execute individual motions
105-
106-
return source.toSource(options.printOptions); // Writes modified AST to file
107-
}
108-
```
109-
110-
## Motions
111-
112-
A motion (aka migration) is what we call specific actions performed within a codemod. For example, `updateBorderWidth` or `removeDeprecatedProps`.
113-
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 highly recommended as
114-
a helpful design pattern to isolate more complicated parts of your codemod into discrete pieces.
115-
116-
**Example:**
117-
118-
```ts
119-
function removeDeprecatedProps(j, source) {
120-
// Some logic here
121-
}
122-
```
123-
124-
Motions can then be applied from the main transform, just like any other function.
125-
126-
```ts
127-
import { hasImportDeclaration } from '@codeshift/utils';
128-
import removeDeprecatedProps from './motions/remove-deprecated-props';
129-
import restructureImports from './motions/restructure-imports';
130-
131-
export default function transformer(file, { jscodeshift: j }, options) {
132-
const source = j(file.source);
133-
134-
// Execute individual motions
135-
removeDeprecatedProps(j, source);
136-
restructureImports(j, source);
137-
138-
return source.toSource(options.printOptions); // Writes modified AST to file
139-
}
140-
```
141-
142-
Each motion receives a reference to the AST (`source`) which it can then manipulate as required.
143-
144-
Alternatively, you can use the utility function [applyMotions](./utils#applymotionsj-source-motions) to run motions in sequence.
145-
146-
```ts
147-
import { applyMotions } from '@codeshift/utils';
148-
import removeDeprecatedProps from './motions/remove-deprecated-props';
149-
import restructureImports from './motions/restructure-imports';
150-
151-
export default function transformer(file, { jscodeshift: j }, options) {
152-
const source = j(file.source);
153-
154-
// Execute a series of motions in order
155-
applyMotions(j, source, [removeDeprecatedProps, restructureImports]);
156-
157-
return source.toSource(options.printOptions);
158-
}
159-
```
160-
161-
## Testing
162-
163-
It's very likely that consumers will run into all sorts of edge-cases when running your transform.
164-
That's why it's important to start by writing some tests to assert it's behavior. Luckily, both [CodeshiftCommunity](./test-utils) & [jscodeshift](https://github.com/facebook/jscodeshift#unit-testing) provides testing utilities to help.
165-
166-
When creating a codemod, it's best to always try to write your tests first (TDD style).
167-
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.
168-
169-
For more information, please see the [testing docs](testing).
170-
171-
**Example:**
172-
173-
```ts
174-
import { applyTransform } from '@codeshift/test-utils';
175-
176-
import * as transformer from '../transform';
177-
178-
describe('MyTransform', () => {
179-
it('should wrap component in a tooltip if name is defined', () => {
180-
const result = applyTransform(
181-
transformer,
182-
`
183-
import MyComponent from 'my-component';
184-
185-
const App = () => {
186-
return <MyComponent name="foo" />;
187-
}
188-
`,
189-
{ parser: 'tsx' },
190-
);
191-
192-
expect(result).toMatchInlineSnapshot(`
193-
"import Tooltip from 'my-tooltip';
194-
import MyComponent from 'my-component';
195-
196-
const App = () => {
197-
return <Tooltip content=\\"foo\\"><MyComponent name=\\"foo\\" /></Tooltip>;
198-
}"
199-
`);
200-
});
201-
});
202-
```
65+
- Your codemods target a closed source package/repository

website/docs/configuration.mdx

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
---
2+
id: configuration
3+
title: Configuration
4+
slug: /configuration
5+
---
6+
7+
All codeshift packages must be coupled with a `codeshift.config.js` file.
8+
This file acts as the entry-point of your codeshift package and is responsible for holding all of the relevant metadata, as well as paths to the transformer functions themselves.
9+
10+
They typically look like this:
11+
12+
```ts
13+
module.exports = {
14+
maintainers: ['danieldelcore'],
15+
description: 'Codemods for the foobar package',
16+
targets: ['foobar'],
17+
transforms: {
18+
'18.0.0': require.resolve('./18.0.0/transform'),
19+
'19.0.0': require.resolve('./19.0.0/transform'),
20+
},
21+
presets: {
22+
'sort-imports': require.resolve('./sort-imports/transform'),
23+
},
24+
};
25+
```
26+
27+
These files should always be in the root directory of your package to ensure `codeshift-cli` has access to it.
28+
It does so by pulling your package directly from NPM and searching the root directory, which by extension means you should always ensure that the config and the transform files are not ignored by npm.
29+
30+
Config files can be written in either JavaScript or TypeScript, depending on your preference.
31+
32+
To check if your config is valid, you can use [the validate command](cli#validate).
33+
34+
## Properties
35+
36+
### `maintainers`
37+
38+
Github usernames of the people that maintain the package, they will be notified on PRs etc.
39+
40+
### `description`
41+
42+
A description of the package and its intended usage
43+
44+
### `transforms`
45+
46+
A key value pair of transforms organized by semver-compatible versions.
47+
48+
For more information see [Guiding Principles](guiding-principles#codemods-should-target-a-version-of-package).
49+
50+
### `presets`
51+
52+
A key value pair of presets organized by kebab case identifiers.
53+
54+
Presets are intended to act as a way to share generic codemods, that are either completely generic or compliment the target package but are not version specific.
55+
56+
Some examples include: `sort-imports`, `format-props`, `remove-comments`, etc.
57+
58+
### `targets`
59+
60+
**Experimental**
61+
62+
Targets list the packages that the codemod package targets.
63+
This is useful for codeshift packages that have codemods targeting multiple related packages at the same time, such as packages from a monorepo.
64+
65+
For example: `targets: ['@foo/bar', '@foo/baz']`

website/docs/consuming.mdx

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,47 +12,49 @@ For usage please refer to the [@codeshift/cli API reference](/docs/cli).
1212

1313
## How to run Community codemods
1414

15-
To apply a codemod from the [Community folder](https://github.com/CodeshiftCommunity/CodeshiftCommunity/tree/main/community) install and use the `@codemod/cli` via `npx`.
15+
To run a codeshift package, install and use the `@codeshift/cli`.
1616

17-
For example, say we want to run transforms for `@mylib/button` and migrate from version 13 to the latest version 14.
17+
- **npm:** `npm install -g @codeshift/cli` or
18+
- **yarn:** `yarn global add @codeshift/cli`
1819

19-
In this case we could try:
20+
For example, say we want to run transforms for `@mylib/button` and migrate from version 13 to the latest version 14, we could run the following:
2021

2122
```
22-
npx codemod-cli --package @mylib/button@14.0.0 project/path/to/src
23+
codemod-cli --package @mylib/button@14.0.0 project/path/to/src
2324
```
2425

2526
The following sequence of events will follow:
2627

27-
1. `npx` will download and run `@codemod/cli`
28-
2. `@codemod/cli` will then attempt to locate a codemod for the `@mylib/button` package matching version `14.0.0`
29-
3. Download the matching transform from NPM
30-
4. Run the transform against the path `project/path/to/src`
28+
1. `@codeshift/cli` will then attempt to download a codeshift package for the `@mylib/button` package matching version `14.0.0`
29+
1. Download the package from NPM
30+
1. Locate the `codeshift.config.js`
31+
1. Attempt to find a `transform` for `14.0.0`
32+
1. Run the transform against the path `project/path/to/src`
3133

3234
## Run codemods in sequence
3335

3436
It's also possible to run a series of codemods, one after the other, to migrate your usage of `@mylib/button` across multiple major versions, from say v14, v15 and finally v16. Assuming codemods for those versions exist.
3537

36-
This is done my providing the `--sequence` (or `-s`) flag to `@codemod/cli`.
38+
This is done my providing the `--sequence` (or `-s`) flag to `@codeshift/cli`.
3739

3840
```
39-
npx codemod-cli --package @mylib/button@14.0.0 --sequence project/path/to/src
41+
codemod-cli --package @mylib/button@14.0.0 --sequence project/path/to/src
4042
```
4143

4244
This time around, we use the provided version (14.0.0) as the start of a semver range between `14.0.0-@latest`.
4345
We then fetch all codemods that match and run them one after another.
4446

4547
## Running local transforms
4648

47-
For codemods not published to the community repo, you can supply your own transform the same way you would with jscodeshift.
49+
For local transform files, not published to the community repo, you can supply your own transform the same way you would with jscodeshift.
4850

4951
```
50-
npx codemod-cli --transform path/to/transform.ts project/path/to/src
52+
codemod-cli --transform path/to/transform.ts project/path/to/src
5153
```
5254

5355
## Parsing TypeScript & Flow
5456

55-
By default `@codemod/cli` will use `babel` as the default parser and only transform files with a `.js` extensions.
57+
By default `@codeshift/cli` will use `babel` as the default parser and only transform files with a `.js` extensions.
5658

5759
If your repo depends on flow or typescript, it's important to remember to specify `ts`, `tsx` or `flow` as the `--parser` and or `jsx, ts, tsx` as `--extensions` to make sure jscodeshift can interpret the files properly.
5860

0 commit comments

Comments
 (0)