Skip to content

Commit

Permalink
feat(mui-codemod): add MUI v6 codemods for element users
Browse files Browse the repository at this point in the history
  • Loading branch information
gregmartDOTin committed Nov 15, 2024
1 parent f83a3a1 commit 3be1a1b
Show file tree
Hide file tree
Showing 43 changed files with 3,830 additions and 28 deletions.
9 changes: 9 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,15 @@
"files": "*.json",
"parser": "jsonc-eslint-parser",
"rules": {}
},
{
"files": [
"**/*.test.js",
"**/*.test.jsx"
],
"env": {
"jest": true
}
}
]
}
Empty file added packages/codemod/CHANGELOG.md
Empty file.
27 changes: 27 additions & 0 deletions packages/codemod/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# @availity/mui-codemod

> Availity MUI v1 Codemods to be used when migrating from @availity/element v0 to v1.
[![Version](https://img.shields.io/npm/v/@availity/mui-codemod.svg?style=for-the-badge)](https://www.npmjs.com/package/@availity/mui-codemod)
[![NPM Downloads](https://img.shields.io/npm/dt/@availity/mui-codemod.svg?style=for-the-badge)](https://www.npmjs.com/package/@availity/mui-codemod)
[![Dependency Status](https://img.shields.io/librariesio/release/npm/@availity/mui-codemod?style=for-the-badge)](https://github.com/Availity/element/blob/main/packages/mui-codemod/package.json)

## Documentation

This package extends the MUI v6 Codemods: [MUI Codemod Docs](https://mui.com/material-ui/migration/upgrade-to-v6/)

Availity standards for design and usage can be found in the [Availity Design Guide](https://zeroheight.com/2e36e50c7)

## Usage

### Migrate Grid props

`npx @availity/mui-codemod@latest v1.0.0/grid-v2-props <path/to/folder>`

### Migrate sx props

`npx @availity/mui-codemod@latest v1.0.0/sx-props <path/to/folder>`

### Migrate system props

`npx @availity/mui-codemod@latest v1.0.0/system-props <path/to/folder>`
7 changes: 7 additions & 0 deletions packages/codemod/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const global = require('../../jest.config.global');

module.exports = {
...global,
displayName: 'codemod',
coverageDirectory: '../../coverage/codemod',
};
5 changes: 5 additions & 0 deletions packages/codemod/jsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"extends": "../../tsconfig.base.json",
"include": ["."],
"exclude": ["dist", "build", "node_modules"]
}
47 changes: 47 additions & 0 deletions packages/codemod/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"name": "@availity/mui-codemod",
"version": "0.0.0",
"description": "Availity MUI v1 Codemods - part of the @availity/element design system",
"keywords": [
"react",
"typescript",
"availity",
"mui"
],
"homepage": "https://availity.github.io/element/?path=/docs/components-codemod-introduction--docs",
"bugs": {
"url": "https://github.com/Availity/element/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/Availity/element.git",
"directory": "packages/codemod"
},
"license": "MIT",
"author": "Availity Developers <[email protected]>",
"bin": "./src/codemod.js",
"engines": {
"node": ">=18.0.0"
},
"scripts": {
"build": "tsup src/index.ts --format esm,cjs --dts",
"dev": "tsup src/index.ts --format esm,cjs --watch --dts",
"clean": "rm -rf dist",
"clean:nm": "rm -rf node_modules",
"publish": "yarn npm publish --tolerate-republish --access public",
"publish:canary": "yarn npm publish --access public --tag canary"
},
"devDependencies": {
"tsup": "^8.0.2",
"typescript": "^5.4.5"
},
"publishConfig": {
"access": "public"
},
"dependencies": {
"@types/jscodeshift": "^0.12.0",
"jscodeshift": "^17.1.1",
"postcss-cli": "^11.0.0",
"yargs": "^17.7.2"
}
}
26 changes: 26 additions & 0 deletions packages/codemod/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "mui-codemod",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "packages/codemod/src",
"projectType": "library",
"tags": [],
"targets": {
"test": {
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/codemod"],
"options": {
"jestConfig": "packages/codemod/jest.config.js"
}
},
"version": {
"executor": "@jscutlery/semver:version",
"options": {
"preset": "conventional",
"commitMessageFormat": "chore({projectName}): release version ${version} [skip ci]",
"tagPrefix": "@availity/{projectName}@",
"trackDeps": true,
"skipCommitTypes": ["docs"]
}
}
}
}
194 changes: 194 additions & 0 deletions packages/codemod/src/codemod.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
#!/usr/bin/env node

const childProcess = require('child_process');
const { promises: fs } = require('fs');
const path = require('path');
const yargs = require('yargs');
const jscodeshiftPackage = require('jscodeshift/package.json');
const postcssCliPackage = require('postcss-cli/package.json');

const jscodeshiftDirectory = path.dirname(require.resolve('jscodeshift'));
const jscodeshiftExecutable = path.join(jscodeshiftDirectory, jscodeshiftPackage.bin.jscodeshift);

const postcssCliDirectory = path.dirname(require.resolve('postcss-cli'));
const postcssExecutable = path.join(postcssCliDirectory, postcssCliPackage.bin.postcss);

async function runJscodeshiftTransform(transform, files, flags, codemodFlags) {
const paths = [
path.resolve(__dirname, './src', `${transform}/index.js`),
path.resolve(__dirname, './src', `${transform}.js`),
path.resolve(__dirname, './node', `${transform}/index.js`),
path.resolve(__dirname, './node', `${transform}.js`),
];

let transformerPath;
let error;
for (const item of paths) {
try {
await fs.stat(item);
error = undefined;
transformerPath = item;
break;
} catch (srcPathError) {
error = srcPathError;
continue;
}
}

if (error) {
if (error?.code === 'ENOENT') {
throw new Error(
`Transform '${transform}' not found. Check out ${path.resolve(__dirname, './README.md for a list of available codemods.')}`,
);
}
throw error;
}

const args = [
jscodeshiftExecutable,
'--transform',
transformerPath,
...codemodFlags,
'--extensions',
'js,ts,jsx,tsx,json',
'--parser',
flags.parser || 'tsx',
'--ignore-pattern',
'**/node_modules/**',
'--ignore-pattern',
'**/*.css'
];

if (flags.dry) {
args.push('--dry');
}
if (flags.print) {
args.push('--print');
}
if (flags.jscodeshift) {
args.push(flags.jscodeshift);
}

args.push(...files);

console.log(`Executing command: jscodeshift ${args.join(' ')}`);
const jscodeshiftProcess = childProcess.spawnSync('node', args, { stdio: 'inherit' });

if (jscodeshiftProcess.error) {
throw jscodeshiftProcess.error;
}
}

const parseCssFilePaths = async (files) => {
const cssFiles = await Promise.all(files.map(async (filePath) => {
const stat = await fs.stat(filePath);
if (stat.isDirectory()) {
return `${filePath}/**/*.css`;
}
if (filePath.endsWith('.css')) {
return filePath;
}

return null;
}),);

return cssFiles.filter(Boolean);
}

async function runPostcssTransform(transform, files) {
const paths = [
path.resolve(__dirname, './src', `${transform}/postcss.config.js`),
path.resolve(__dirname, './node', `${transform}/postcss.config.js`),
];

let configPath;
let error;
for (const item of paths) {
try {
await fs.stat(item);
error = undefined;
configPath = item;
break;
} catch (srcPathError) {
error = srcPathError;
continue;
}
}

if (error) {
if (error?.code !== 'ENOENT') {
throw error;
}
} else {
const cssPaths = await parseCssFilePaths(files);

if (cssPaths.length > 0) {
const args = [
postcssExecutable,
...cssPaths,
'--config',
configPath,
'--replace',
'--verbose',
];

console.log(`Executing command: postcss ${args.join(' ')}`);
const postCssProcess = childProcess.spawnSync('node', args, { stdio: 'inherit' });

if (postCssProcess.error) {
throw postCssProcess.error;
}
}
}
}

function run(argv) {
const { codemod, paths, ...flags } = argv;
const files = paths.map((filePath) => path.resolve(filePath));

runJscodeshiftTransform(codemod, files, flags, argv._);
runPostcssTransform(codemod, files);
}

yargs.command({
command: '$0 <codemod> <paths...>',
describe: 'Applies a `@mui/codemod` to the specified paths',
builder: (command) => {
return command
.positional('codemod', {
description: 'The name of the codemod',
type: 'string'
})
.positional('paths', {
array: true,
description: 'Paths forwarded to `jscodeshift`',
type: 'string',
})
.option('dry', {
description: 'dry run (no changes are made to files)',
default: false,
type: 'boolean'
})
.option('parser', {
description: 'which parser for jscodeshift to use',
default: 'tsx',
type: 'string'
})
.option('print', {
description: 'print transformed files to stdout, useful for development',
default: false,
type: 'boolean'
})
.option('jscodeshift', {
description: '(Advanced) Pass options directly to jscodeshift',
default: false,
type: 'string'
});
},
handler: run,
})
.scriptName('npx @availity/mui-codemod')
.example('$0 v4.0.0/theme-spacing-api src')
.example('$0 v5.0.0/component-rename-prop src -- --component=Grid --from=prop --to=newProp')
.help()
.parse();
Loading

0 comments on commit 3be1a1b

Please sign in to comment.