Skip to content

Commit

Permalink
feat: add format effected files (#134)
Browse files Browse the repository at this point in the history
* feat: add format effected files

* fix: typo

* feat: change to use eslint

* feat: add format to use prettier through option
  • Loading branch information
winchesHe authored Jan 14, 2025
1 parent af02fbe commit a27371b
Show file tree
Hide file tree
Showing 12 changed files with 141 additions and 8 deletions.
7 changes: 5 additions & 2 deletions packages/codemod/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ The CLI provides a comprehensive suite of tools to migrate your codebase from Ne
## Quick Start

> **Note**: The heroui CLI requires [Node.js](https://nodejs.org/en) _18.17.x_ or later
>
> **Note**: If running in monorepo, you need to run the command in the root of your monorepo
You can start using @heroui/codemod in one of the following ways:

Expand Down Expand Up @@ -49,9 +51,10 @@ Options:
-v, --version Output the current version
-d, --debug Enable debug mode
-h, --help Display help for command
-f, --format Format the affected files with Prettier

Commands:
migrate [projectPath] Migrate your codebase to use heroui
migrate [projectPath] Migrate your codebase to use heroui
```

## Codemod Arguments
Expand Down Expand Up @@ -141,7 +144,7 @@ Example:
Migrate your entire codebase from NextUI to heroui. You can choose which codemods to run during the migration process.

```bash
heroui-codemod migrate [projectPath]
heroui-codemod migrate [projectPath] [--format]
```

Example:
Expand Down
26 changes: 25 additions & 1 deletion packages/codemod/src/actions/migrate-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@ import chalk from 'chalk';
import {confirmClack} from 'src/prompts/clack';

import {NEXTUI_PREFIX} from '../constants/prefix';
import {lintAffectedFiles} from '../helpers/actions/lint-affected-files';
import {migrateCssVariables} from '../helpers/actions/migrate/migrate-css-variables';
import {migrateImportPackageWithPaths} from '../helpers/actions/migrate/migrate-import';
import {migrateJson} from '../helpers/actions/migrate/migrate-json';
import {migrateNextuiProvider} from '../helpers/actions/migrate/migrate-nextui-provider';
import {migrateNpmrc} from '../helpers/actions/migrate/migrate-npmrc';
import {migrateTailwindcss} from '../helpers/actions/migrate/migrate-tailwindcss';
import {findFiles} from '../helpers/find-files';
import {getStore, storeParsedContent, storePathsRawContent} from '../helpers/store';
import {getOptionsValue} from '../helpers/options';
import {affectedFiles, getStore, storeParsedContent, storePathsRawContent} from '../helpers/store';
import {transformPaths} from '../helpers/transform';
import {getCanRunCodemod} from '../helpers/utils';

Expand Down Expand Up @@ -144,5 +146,27 @@ export async function migrateAction(projectPaths?: string[], options = {} as Mig
step++;
}

const format = getOptionsValue('format');
/** ======================== 7. Formatting affected files (Optional) ======================== */
const runFormatAffectedFiles = affectedFiles.size > 0;

// If user using format option, we don't need to use eslint
if (runFormatAffectedFiles && !format) {
p.log.step(`${step}. Formatting affected files (Optional)`);
const selectMigrateNpmrc = await confirmClack({
message: `Do you want to format affected files? (${affectedFiles.size})`
});

if (selectMigrateNpmrc) {
await lintAffectedFiles();
}
step++;
}

// Directly linting affected files don't need to ask user
if (format) {
await lintAffectedFiles();
}

p.outro(chalk.green('✅ Migration completed!'));
}
10 changes: 10 additions & 0 deletions packages/codemod/src/helpers/actions/lint-affected-files.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import {tryLintFile} from '../lint';
import {affectedFiles} from '../store';

export async function lintAffectedFiles() {
try {
await tryLintFile(Array.from(affectedFiles));
} catch (error) {
return;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {HEROUI_CSS_VARIABLES_PREFIX, NEXTUI_CSS_VARIABLES_PREFIX} from '../../../constants/prefix';
import {getStore, writeFileAndUpdateStore} from '../../store';
import {getStore, updateAffectedFiles, writeFileAndUpdateStore} from '../../store';

export function migrateCssVariables(files: string[]) {
for (const file of files) {
Expand All @@ -13,6 +13,7 @@ export function migrateCssVariables(files: string[]) {
);

writeFileAndUpdateStore(file, 'rawContent', content);
updateAffectedFiles(file);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import jscodeshift from 'jscodeshift';

import {HEROUI_PREFIX, NEXTUI_PREFIX} from '../../../constants/prefix';
import {type StoreObject, getStore, writeFileAndUpdateStore} from '../../store';
import {
type StoreObject,
getStore,
updateAffectedFiles,
writeFileAndUpdateStore
} from '../../store';

/**
* Migrate the import package will directly write the file
Expand All @@ -24,6 +29,7 @@ export function migrateImportPackageWithPaths(paths: string[]) {
if (dirtyFlag) {
// Write the modified content back to the file
writeFileAndUpdateStore(path, 'parsedContent', parsedContent);
updateAffectedFiles(path);
}
// eslint-disable-next-line no-empty
} catch {}
Expand Down
3 changes: 2 additions & 1 deletion packages/codemod/src/helpers/actions/migrate/migrate-json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {Logger} from '@helpers/logger';
import {HEROUI_PREFIX, NEXTUI_PREFIX} from '../../../constants/prefix';
import {fetchPackageLatestVersion} from '../../https';
import {safeParseJson} from '../../parse';
import {getStore, writeFileAndUpdateStore} from '../../store';
import {getStore, updateAffectedFiles, writeFileAndUpdateStore} from '../../store';

const DEFAULT_INDENT = 2;

Expand Down Expand Up @@ -51,6 +51,7 @@ export async function migrateJson(files: string[]) {
const indent = detectIndent(content);

writeFileAndUpdateStore(file, 'rawContent', JSON.stringify(json, null, indent));
updateAffectedFiles(file);
}
})
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {HEROUI_PROVIDER, NEXTUI_PROVIDER} from '../../../constants/prefix';
import {getStore, writeFileAndUpdateStore} from '../../store';
import {getStore, updateAffectedFiles, writeFileAndUpdateStore} from '../../store';

import {migrateByRegex} from './migrate-common';

Expand All @@ -26,6 +26,7 @@ export function migrateNextuiProvider(paths: string[]) {
if (dirtyFlag) {
// Write the modified content back to the file
writeFileAndUpdateStore(path, 'rawContent', rawContent);
updateAffectedFiles(path);
}
// eslint-disable-next-line no-empty
} catch {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
NEXTUI_PLUGIN,
NEXTUI_PREFIX
} from '../../../constants/prefix';
import {getStore, writeFileAndUpdateStore} from '../../store';
import {getStore, updateAffectedFiles, writeFileAndUpdateStore} from '../../store';

import {migrateCallExpressionName, migrateImportName} from './migrate-common';
import {migrateImportPackage} from './migrate-import';
Expand Down Expand Up @@ -56,6 +56,7 @@ export function migrateTailwindcss(paths: string[]) {

if (dirtyFlag) {
writeFileAndUpdateStore(path, 'parsedContent', parsedContent);
updateAffectedFiles(path);
}
}
}
58 changes: 58 additions & 0 deletions packages/codemod/src/helpers/lint.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import {getOptionsValue} from './options';
import {getStore, writeFileAndUpdateStore} from './store';

async function tryImportPackage(packageName: string) {
try {
return await import(packageName);
} catch {
return null;
}
}

export async function lintWithESLint(filePaths: string[]) {
const eslintPkg = await tryImportPackage('eslint');

if (eslintPkg) {
const ESLint = eslintPkg.ESLint;
const eslint = new ESLint({
fix: true
});
const result = await eslint.lintFiles(filePaths);

await ESLint.outputFixes(result);
}
}

export async function lintWithPrettier(filePaths: string[]) {
const prettier = await tryImportPackage('prettier');
const options = await prettier.resolveConfig(process.cwd());

if (prettier) {
await Promise.all(
filePaths.map(async (filePath) => {
const rawContent = getStore(filePath, 'rawContent');
const formattedContent = await prettier.format(rawContent, {
options,
parser: 'typescript'
});

writeFileAndUpdateStore(filePath, 'rawContent', formattedContent);
})
);
}
}

/**
* Try linting a file with ESLint or Prettier
*/
export async function tryLintFile(filePaths: string[]) {
try {
if (getOptionsValue('format')) {
await lintWithPrettier(filePaths);
} else {
await lintWithESLint(filePaths);
}
} catch {
return;
}
}
17 changes: 17 additions & 0 deletions packages/codemod/src/helpers/options.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export const CODEMOD_OPTIONS = {
format: false
};

export function initOptions(options: {format: boolean}) {
const {format} = options;

setOptionsValue('format', format);
}

export function setOptionsValue(key: keyof typeof CODEMOD_OPTIONS, value: boolean) {
CODEMOD_OPTIONS[key] = value;
}

export function getOptionsValue<T extends keyof typeof CODEMOD_OPTIONS>(key: T) {
return CODEMOD_OPTIONS[key];
}
6 changes: 6 additions & 0 deletions packages/codemod/src/helpers/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,9 @@ export function writeFileAndUpdateStore<K extends ExcludeStoreKey>(
updateStore(path, key, value);
key === 'parsedContent' && updateStore(path, 'rawContent', data.rawContent);
}

export const affectedFiles = new Set<string>();

export function updateAffectedFiles(path: string) {
affectedFiles.add(path);
}
5 changes: 5 additions & 0 deletions packages/codemod/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import pkg from '../package.json';
import {codemodAction} from './actions/codemod-action';
import {migrateAction} from './actions/migrate-action';
import {DEBUG} from './helpers/debug';
import {initOptions} from './helpers/options';
import {codemods} from './types';

const nextui = new Command();
Expand All @@ -22,6 +23,7 @@ nextui
.argument('[codemod]', `Specify which codemod to run\nCodemods: ${codemods.join(', ')}`)
.allowUnknownOption()
.option('-d, --debug', 'Enable debug mode')
.option('-f, --format', 'Format the affected files with Prettier')
.action(codemodAction);

nextui
Expand All @@ -33,6 +35,9 @@ nextui
nextui.hook('preAction', async (command) => {
const options = (command as SAFE_ANY).rawArgs.slice(2);
const debug = options.includes('--debug') || options.includes('-d');
const format = options.includes('--format') || options.includes('-f');

initOptions({format});

DEBUG.enabled = debug;
});
Expand Down

0 comments on commit a27371b

Please sign in to comment.