Skip to content
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
b42ec42
feat(bezier-codemod): npm init
sungik-choi May 31, 2023
1709a7e
feat(bezier-codemod): setting up the default test environment
sungik-choi May 31, 2023
16447a3
feat(bezier-codemod): setting package preference
sungik-choi May 31, 2023
36d8bae
feat(bezier-codemod): basic implementation of the icons-to-bezier-ico…
sungik-choi May 31, 2023
e5621ca
chore(bezier-codemod): fix eslint configuration
sungik-choi May 31, 2023
4ae73dc
test(bezier-codemod/fixtures): add ts-nocheck
sungik-choi May 31, 2023
e7bafd7
refactor(bezier-codemod): refactoring to async functions
sungik-choi May 31, 2023
401780b
refactor(bezier-codemod): convert to sync func and remove throw state…
sungik-choi May 31, 2023
fcb488f
feat(bezier-codemod): remove comment statement related logic and move…
sungik-choi Jun 1, 2023
8c7f18f
feat(bezier-codemod): set up a temporary ink app
sungik-choi Jun 1, 2023
051de78
feat(bezier-codemod): implement the cli ui
sungik-choi Jun 1, 2023
e543b33
build(bezier-codemod): set package.json
sungik-choi Jun 1, 2023
5ac6afb
chore(bezier-codemod): update yarn.lock and add lint staged
sungik-choi Jun 1, 2023
a395413
chore(bezier-codemod): jest only changed
sungik-choi Jun 1, 2023
a2209df
docs: update readme
sungik-choi Jun 1, 2023
d7ed76e
chore(bezier-codemod): update package description
sungik-choi Jun 1, 2023
68b43c4
chore(bezier-codemod): update doc
sungik-choi Jun 1, 2023
5082df1
chore(changeset): add changeset
sungik-choi Jun 1, 2023
5f52ca6
fix(bezier-codemod): fix lint error
sungik-choi Jun 1, 2023
cdc1367
refactor(bezier-codemod): split project into separate module
sungik-choi Jun 1, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/spotty-baboons-guess.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@channel.io/bezier-codemod": minor
---

Add icons-to-bezier-icons transformer
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
|---|---|
| [bezier-react](packages/bezier-react) | React components library that implements Bezier design system. |
| [bezier-icons](packages/bezier-icons) | Icon library that implements Bezier design system. |
| [bezier-codemod](packages/bezier-codemod) | Codemod transformations to help upgrade app using Bezier design system. |
| [bezier-figma-plugin](packages/bezier-figma-plugin) | Figma plugin that helps build Bezier design system and increase productivity. |

## Commands
Expand Down
4 changes: 4 additions & 0 deletions packages/bezier-codemod/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules
dist

**/tests/**/fixtures/**/*
36 changes: 36 additions & 0 deletions packages/bezier-codemod/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
module.exports = {
root: true,
extends: ['bezier'],
parserOptions: {
tsconfigRootDir: __dirname,
project: './tsconfig.eslint.json',
},
rules: {
'no-restricted-imports': 'off',
'sort-imports': [
'error',
{
ignoreDeclarationSort: true,
},
],
'import/order': [
'error',
{
'newlines-between': 'always',
alphabetize: { order: 'asc' },
groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index'],
pathGroupsExcludedImportTypes: ['react'],
pathGroups: [
{
pattern: 'react',
group: 'external',
position: 'before',
},
],
},
],
'react/react-in-jsx-scope': 'off',
'react/jsx-props-no-spreading': 'off',
'@typescript-eslint/naming-convention': 'off',
},
}
3 changes: 3 additions & 0 deletions packages/bezier-codemod/.lintstagedrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"**/*.(js|ts)?(x)": "yarn lint"
}
38 changes: 38 additions & 0 deletions packages/bezier-codemod/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Bezier Codemod

Codemod transformations to help upgrade app using Bezier design system.

## Usage

In your terminal, navigate into your project's folder, then run:

```bash
npx @channel.io/bezier-codemod
```

## Transformations

### Icons to Bezier icons

**`icons-to-bezier-icons`**

Update the import syntax for the icon source moved from `@channel.io/bezier-react` to `@channel.io/bezier-icons`.

For example:

```tsx
import React from 'react'
import { AllIcon, Button, CheckIcon as CheckIconSource, Icon, type IconName, IconSize } from '@channel.io/bezier-react'

import Foo from './foo'
```

Transforms into:

```tsx
import React from 'react'
import { AllIcon, CheckIcon as CheckIconSource, type IconName } from '@channel.io/bezier-icons'
import { Button, Icon, IconSize } from '@channel.io/bezier-react'

import Foo from './foo'
```
19 changes: 19 additions & 0 deletions packages/bezier-codemod/jest.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/** @type {import('ts-jest').JestConfigWithTsJest} */
module.exports = {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

preset: 'ts-jest/presets/default-esm',
moduleNameMapper: {
'^(\\.{1,2}/.*)\\.js$': '$1',
},
transform: {
// '^.+\\.[tj]sx?$' to process js/ts with `ts-jest`
// '^.+\\.m?[tj]sx?$' to process js/ts/mjs/mts with `ts-jest`
'^.+\\.tsx?$': [
'ts-jest',
{
useESM: true,
},
],
},
testEnvironment: 'node',
testRegex: '\\.test\\.ts$',
}
49 changes: 49 additions & 0 deletions packages/bezier-codemod/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"name": "@channel.io/bezier-codemod",
"version": "0.0.0",
"description": "Codemod transformations to help upgrade app using Bezier design system.",
"repository": {
"type": "git",
"url": "https://github.com/channel-io/bezier-react",
"directory": "packages/bezier-codemod"
},
"author": "Channel Corp.",
"license": "Apache-2.0",
"bin": "dist/cli.js",
"type": "module",
"engines": {
"node": ">=16"
},
"scripts": {
"build": "tsc --build --verbose",
"dev": "tsc --watch",
"lint": "TIMING=1 eslint --cache .",
"typecheck": "tsc --noEmit",
"test": "jest --onlyChanged",
"clean": "rm -rf dist node_modules .turbo .eslintcache"
},
"files": [
"dist"
],
"dependencies": {
"@inkjs/ui": "^1.0.0",
"ink": "^4.1.0",
"meow": "^11.0.0",
"react": "^18.2.0",
"ts-morph": "^18.0.0"
},
"devDependencies": {
"@types/jest": "^29.5.1",
"@types/node": "^20.2.5",
"@types/react": "^18.0.32",
"eslint-config-bezier": "workspace:*",
"jest": "^29.5.0",
"ts-jest": "^29.1.0",
"ts-node": "^10.9.1",
"tsconfig": "workspace:*"
},
"keywords": [
"codemod",
"channel"
]
}
194 changes: 194 additions & 0 deletions packages/bezier-codemod/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
import React, {
useCallback,
useEffect,
useState,
} from 'react'

import {
Select,
type SelectProps,
Spinner,
StatusMessage,
TextInput,
} from '@inkjs/ui'
import {
Box,
Text,
useApp,
} from 'ink'
import {
IndentationText,
NewLineKind,
Project,
QuoteKind,
} from 'ts-morph'

import iconsToBezierIcons from './transforms/icons-to-bezier-icons.js'

const project = new Project({
manipulationSettings: {
indentationText: IndentationText.TwoSpaces,
newLineKind: NewLineKind.LineFeed,
quoteKind: QuoteKind.Single,
usePrefixAndSuffixTextForRename: true,
useTrailingCommas: false,
},
})

enum Step {
SelectTransformer,
InputFiles,
Transforming,
Done,
}

enum Option {
IconsToBezierIcons = 'icons-to-bezier-icons',
Exit = 'Exit',
}

type TransformName = Exclude<Option, Option.Exit>

const transformMap = {
[Option.IconsToBezierIcons]: iconsToBezierIcons,
}

const options = (Object.keys(transformMap) as Option[]).map((transformName) => ({
label: transformName,
value: transformName,
})).concat({
label: Option.Exit,
value: Option.Exit,
})

function formatExecutionTime(executionTime: number) {
const seconds = Math.round(executionTime / 1000 * 1000) / 1000
return `${seconds.toFixed(3)}s`
}

function App() {
const { exit } = useApp()

const [step, setStep] = useState(Step.SelectTransformer)
const [transformName, setTransformName] = useState<TransformName | null>(null)
const [filePath, setFilePath] = useState('')
const [executionTime, setExecutionTime] = useState(0)
const [transformedFileNum, setTransformedFileNum] = useState(0)

const onSelectTransform = useCallback((value: Option) => {
if (value === Option.Exit) {
exit()
return
}
setTransformName(value)
setStep(Step.InputFiles)
}, [exit])

const onSubmitFilePath = useCallback((value: string) => {
if (!transformName) { return }
setFilePath(value)
setStep(Step.Transforming)
}, [transformName])

useEffect(function main() {
if (step !== Step.Transforming) { return }

/**
* FIXME: This timeout is a hack to make sure the UI is updated before the transform starts.
* Otherwise, the UI will be stuck on the previous step.
*/
setTimeout(() => {
const startTime = performance.now()

async function transformSourceFiles() {
const sourceFiles = project.addSourceFilesAtPaths(filePath)

await Promise.all(
sourceFiles.map(async (sourceFile) => {
if (!transformName) { return }
const transform = transformMap[transformName]
const isTransformed = transform(sourceFile)
if (isTransformed) {
setTransformedFileNum(prev => prev + 1)
}
await sourceFile.save()
}),
)

const endTime = performance.now()
const totalExecutionTime = endTime - startTime
setExecutionTime(totalExecutionTime)
setStep(Step.Done)
}

transformSourceFiles()
}, 100)
}, [
step,
transformName,
filePath,
])

return (
<Box flexDirection="column">
{ step === Step.SelectTransformer && (
<>
<Text bold>
💬 Please select the transformer:
</Text>
<Select
options={options}
onChange={onSelectTransform as SelectProps['onChange']}
/>
</>
) }

{ step === Step.InputFiles && (
<>
<Text bold>
💬 Please input the file path. You can use a glob pattern:
</Text>
<TextInput
placeholder="**/*{.ts,.tsx}"
onSubmit={onSubmitFilePath}
/>
</>
) }

{ step === Step.Transforming && (
<Box marginTop={1}>
<Spinner label="Transforming" />
</Box>
) }

{ step === Step.Done && (
<Box
marginTop={1}
paddingLeft={1}
borderStyle="round"
borderColor="green"
flexDirection="column"
>
<StatusMessage variant="success">
<Text bold>
Transformation complete
</Text>
</StatusMessage>
<Box
paddingLeft={2}
flexDirection="column"
>
<Text>
Number of transformed files: { transformedFileNum }
</Text>
<Text>
Execution time: { formatExecutionTime(executionTime) }
</Text>
</Box>
</Box>
) }
</Box>
)
}

export default App
27 changes: 27 additions & 0 deletions packages/bezier-codemod/src/cli.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/usr/bin/env node
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line should be added to all files that will be executed through the command line. It's called a Shebang, and basically, it specifies what interpreter the file should be passed to for execution in Unix-like systems.

import React from 'react'

import { render } from 'ink'
import meow from 'meow'

import App from './App.js'

meow(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

`
Usage:
$ npx @channel.io/bezier-codemod

More info:
https://github.com/channel-io/bezier-react
`,
{
importMeta: import.meta,
flags: {
name: {
type: 'string',
},
},
},
)

render(<App />)
Loading