Skip to content

Commit be0f9a7

Browse files
feat: add button element to <Button /> Wildcard component codemod (#71)
1 parent ff8f571 commit be0f9a7

File tree

168 files changed

+3270
-458
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

168 files changed

+3270
-458
lines changed

.eslintrc.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ module.exports = {
1111
jsx: true,
1212
},
1313
EXPERIMENTAL_useSourceOfProjectReferenceRedirect: true,
14-
project: ['./tsconfig.eslint.json', './packages/*/tsconfig.json'],
14+
project: ['./tsconfig.eslint.json', './packages/!(demo-app)/tsconfig.json'],
1515
tsconfigRootDir: __dirname,
1616
warnOnUnsupportedTypeScriptVersion: false,
1717
},
@@ -23,5 +23,6 @@ module.exports = {
2323
rules: {
2424
'no-sync': 'off',
2525
'arrow-body-style': ['error', 'always'],
26+
'ban/ban': 'off',
2627
},
2728
}

.github/workflows/lsif.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,15 @@ jobs:
88
strategy:
99
matrix:
1010
root:
11-
- packages/codemod
11+
- packages/cli
12+
- packages/common
13+
- packages/demo-app
14+
- packages/eslint-plugin
15+
- packages/toolkit-css
16+
- packages/toolkit-packages
17+
- packages/toolkit-ts
18+
- packages/transforms
19+
1220
steps:
1321
- uses: actions/checkout@v2
1422
- name: Setup Node.js

README.md

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,28 @@
11
# @sourcegraph/codemod
22

3-
[![npm](https://img.shields.io/npm/v/@sourcegraph/codemod.svg)](https://www.npmjs.com/package/@sourcegraph/codemod)
4-
[![downloads](https://img.shields.io/npm/dt/@sourcegraph/codemod.svg)](https://www.npmjs.com/package/@sourcegraph/codemod)
5-
[![build](https://img.shields.io/github/workflow/status/sourcegraph/codemod/build/master)](https://github.com/sourcegraph/codemod/actions?query=branch%3Amaster+workflow%3Abuild)
6-
[![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://github.com/prettier/prettier)
7-
[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)
3+
A toolkit for writing codemods powered by [ts-morph](https://github.com/dsherret/ts-morph) and [PostCSS](https://github.com/postcss/postcss).
84

9-
A collection of codemods powered by TS-Morph and PostCSS
10-
11-
## Use
5+
## Setup
126

137
```sh
14-
yarn --cwd ./packages/codemod transform global-css-to-css-modules
8+
yarn
159
```
1610

17-
## Build
11+
## Use
1812

1913
```sh
20-
yarn
21-
yarn build
14+
yarn transform --help
2215
```
2316

24-
## Test
17+
## Other commands
2518

2619
```sh
20+
yarn build
21+
yarn build:clean
22+
yarn build:watch
23+
2724
yarn test
25+
yarn format
26+
yarn format:check
27+
yarn lint
2828
```
29-
30-
## Release
31-
32-
Releases are done automatically in CI when commits are merged into master by analyzing [Conventional Commit Messages](https://conventionalcommits.org/).
33-
After running `yarn`, commit messages will be linted automatically when committing though a git hook.
34-
The git hook can be circumvented for fixup commits with [git's `fixup!` autosquash feature](https://fle.github.io/git-tip-keep-your-branch-clean-with-fixup-and-autosquash.html), or by passing `--no-verify` to `git commit`.
35-
You may have to rebase a branch before merging to ensure it has a proper commit history, or squash merge with a manually edited commit message that conforms to the convention.

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,12 @@
99
"url": "https://github.com/sourcegraph/codemod.git"
1010
},
1111
"scripts": {
12+
"transform": "yarn workspace @sourcegraph/codemod-cli transform",
1213
"test": "jest",
1314
"release": "semantic-release",
1415
"format": "prettier '**/*.{js?(on),ts?(x),scss,md,yml}' --write --list-different --ignore-path ./.prettierignore",
1516
"format:check": "yarn format --write=false",
16-
"lint": "eslint .",
17+
"lint": "eslint --ignore-pattern 'demo-app' --cache .",
1718
"build": "tsc --build",
1819
"build:clean": "tsc --build --clean && rimraf ./packages/*/dist ./packages/*/*.tsbuildinfo",
1920
"build:watch": "tsc --build --watch",
@@ -65,6 +66,7 @@
6566
"jest": "^27.0.6",
6667
"prettier": "^2.4.1",
6768
"semantic-release": "^17.4.4",
69+
"ts-dedent": "^2.2.0",
6870
"ts-jest": "^27.1.2"
6971
},
7072
"resolutions": {

packages/cli/README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# CLI
2+
3+
The CLI interface for running codemods created with this monorepo toolkit. It's responsible for:
4+
5+
1. Processing CLI arguments.
6+
2. Loading transforms.
7+
3. Running transforms on multiple files.
8+
4. Outputting analytics messages.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import baseConfig from '../../jest.config.base'
44

55
const config: InitialOptionsTsJest = {
66
...baseConfig,
7-
displayName: 'codemod',
7+
displayName: 'codemod-cli',
88
rootDir: __dirname,
99
}
1010

packages/cli/package.json

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"private": true,
3+
"name": "@sourcegraph/codemod-cli",
4+
"version": "1.0.0",
5+
"description": "@sourcegraph/codemod-cli",
6+
"license": "Apache-2.0",
7+
"main": "dist/index.js",
8+
"types": "dist/index.d.ts",
9+
"bin": "./dist/index.js",
10+
"scripts": {
11+
"build": "tsc --build ./tsconfig.build.json",
12+
"build:watch": "tsc --build --watch ./tsconfig.build.json",
13+
"build:clean": "tsc --build --clean ./tsconfig.build.json && rimraf dist ./*.tsbuildinfo",
14+
"typecheck": "tsc --noEmit",
15+
"test": "jest",
16+
"format": "prettier --write \"./**/*.{ts,js,json,md}\" --ignore-path ../../.prettierignore",
17+
"transform": "ts-node-transpile-only ./src/cli.ts",
18+
"lint": "eslint './src/**/*.ts?(x)'"
19+
},
20+
"dependencies": {
21+
"@sourcegraph/codemod-common": "1.0.0"
22+
}
23+
}

packages/cli/src/cli.ts

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
// Used for parsing a transform module.
2+
import 'ts-node/register/transpile-only'
3+
import path from 'path'
4+
5+
import { Command } from 'commander'
6+
import signale from 'signale'
7+
import { dedent } from 'ts-dedent'
8+
// TODO: replace project with generic interface that can be used for CSS codemods.
9+
import { Project } from 'ts-morph'
10+
11+
import { logRequiredManualChanges } from '@sourcegraph/codemod-common'
12+
13+
import { Codemod, CodemodContext, TransformOptions } from './types'
14+
15+
const program = new Command()
16+
17+
interface CodemodCliOptions extends TransformOptions {
18+
write: boolean
19+
format: boolean
20+
transform: string
21+
}
22+
23+
const PROJECT_ROOT = path.resolve(__dirname, '../../../')
24+
25+
program
26+
// TODO: make it `true` by default after switching to fast bulk format.
27+
.option('-f, --format [format]', 'Format Typescript source files with ESLint', false)
28+
.option('-w, --write [write]', 'Persist codemod changes to the filesystem', false)
29+
.option('-t, --transform <transform>', 'Absolute or relative to project root path to a transform module')
30+
.argument('<fileGlob>', 'Absolute or relative to project root file glob to change files based on')
31+
.allowUnknownOption(true)
32+
.enablePositionalOptions(true)
33+
.addHelpText(
34+
'after',
35+
dedent`
36+
37+
Transform-specific options can be passed via using '--option=value' syntax:
38+
yarn transform --write --tagToConvert=Link -t ./transformPath.ts 'globPath/**/*.{ts,tsx}'
39+
`
40+
)
41+
.action(async (commandArgument: string, options: CodemodCliOptions) => {
42+
const { fileGlob, transformOptions } = parseOptions(commandArgument)
43+
const { write: shouldWriteFiles, format: shouldFormat, transform } = options
44+
45+
const projectGlob = path.isAbsolute(fileGlob) ? fileGlob : path.join(PROJECT_ROOT, fileGlob)
46+
const transformPath = path.isAbsolute(transform) ? transform : path.join(PROJECT_ROOT, transform)
47+
48+
signale.start(`Starting codemod "${transformPath}" with the project glob "${projectGlob}".`)
49+
50+
const project = new Project()
51+
project.addSourceFilesAtPaths(projectGlob)
52+
53+
const transformExports = Object.values(await import(transformPath))
54+
if (transformExports.length !== 1) {
55+
throw new Error('Transform file should have one named export with the transform function.')
56+
}
57+
58+
const [codemod] = transformExports
59+
const codemodContext: CodemodContext = {
60+
project,
61+
shouldWriteFiles,
62+
shouldFormat,
63+
transformOptions,
64+
}
65+
66+
const results = await (codemod as Codemod)(codemodContext)
67+
68+
results.map(result => {
69+
logRequiredManualChanges(result.manualChangesReported)
70+
})
71+
72+
if (shouldWriteFiles) {
73+
signale.await('Persisting codemod changes to the filesystem...')
74+
await Promise.all(
75+
results.map(result => {
76+
return result.fsWritePromise
77+
})
78+
)
79+
signale.complete('Persisting codemod changes completed.')
80+
} else {
81+
for (const file of results.flatMap(result => {
82+
return result.files
83+
})) {
84+
signale.log(file?.source)
85+
}
86+
}
87+
88+
signale.success('Codemod is applied!')
89+
})
90+
91+
program.parse(process.argv)
92+
93+
interface ParseOptionsResult {
94+
fileGlob: string
95+
transformOptions: TransformOptions
96+
}
97+
98+
function parseOptions(commandArgument: string): ParseOptionsResult {
99+
const { unknown } = program.parseOptions(process.argv)
100+
101+
// TODO: find a better way to process and validate `transformOptions`.
102+
const fileGlob = unknown.pop() || commandArgument
103+
104+
const transformOptions = unknown.reduce<Record<string, unknown>>((result, key) => {
105+
const [name, value = true] = key.split('=')
106+
result[name.replace('--', '')] = value
107+
108+
return result
109+
}, {})
110+
111+
return { fileGlob, transformOptions }
112+
}

packages/cli/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './types'

packages/cli/src/types.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// TODO: replace with generic interfaces that can be reused for CSS transforms.
2+
import { Project, SourceFile } from 'ts-morph'
3+
4+
import { ManualChangesReported } from '@sourcegraph/codemod-common'
5+
6+
export interface TransformOptions extends Object {}
7+
8+
export interface CodemodContext<T extends TransformOptions = TransformOptions> {
9+
project: Project
10+
transformOptions?: T
11+
/** If `true` persist changes made by the codemod to the filesystem. */
12+
shouldWriteFiles?: boolean
13+
/** If `true` format Typescript source files with `prettier-eslint`. */
14+
shouldFormat?: boolean
15+
}
16+
17+
export interface CodemodResultFile {
18+
source: string
19+
path: string
20+
}
21+
22+
export interface CodemodResult {
23+
target: SourceFile
24+
manualChangesReported: ManualChangesReported
25+
files?: CodemodResultFile[]
26+
fsWritePromise?: Promise<unknown>
27+
}
28+
29+
export type Codemod<T extends TransformOptions = TransformOptions> = (
30+
codemodContext: CodemodContext<T>
31+
) => Promise<CodemodResult[]>

0 commit comments

Comments
 (0)