44 *
55 * @see {@link https://github.com/vercel/next.js/blob/dc9f30c/packages/next-codemod/bin/cli.ts }
66 */
7- import { execaSync } from "execa " ;
7+ import { Command } from "commander " ;
88import { globbySync } from "globby" ;
9- import inquirer , { type DistinctQuestion } from "inquirer" ;
10- import isGitClean from "is-git-clean" ;
11- import meow , { type AnyFlags } from "meow" ;
9+ import { execFileSync , spawnSync } from "node:child_process" ;
1210import { createRequire } from "node:module" ;
1311import path from "node:path" ;
1412import { fileURLToPath } from "node:url" ;
1513import pc from "picocolors" ;
14+ import prompts from "prompts" ;
1615
1716const { yellow } = pc ;
1817
@@ -27,7 +26,11 @@ export function checkGitStatus(force: boolean) {
2726 let clean = false ;
2827 let errorMessage = "Unable to determine if git directory is clean" ;
2928 try {
30- clean = isGitClean . sync ( process . cwd ( ) ) ;
29+ const stdout = execFileSync ( "git" , [ "status" , "--porcelain" ] , {
30+ cwd : process . cwd ( ) ,
31+ encoding : "utf8" ,
32+ } ) ;
33+ clean = stdout . trim ( ) . length === 0 ;
3134 errorMessage = "Git directory is not clean" ;
3235 } catch ( err : unknown ) {
3336 const stderr =
@@ -63,7 +66,7 @@ interface RunTransformOptions {
6366 dry ?: boolean ;
6467 print ?: boolean ;
6568 runInBand ?: boolean ;
66- jscodeshift ?: readonly string [ ] ;
69+ jscodeshift ?: string [ ] ;
6770}
6871
6972export function runTransform ( {
@@ -89,6 +92,7 @@ export function runTransform({
8992 }
9093
9194 args . push ( "--verbose=2" ) ;
95+ args . push ( "--parser=tsx" ) ;
9296
9397 args . push ( "--ignore-pattern=**/node_modules/**" ) ;
9498 args . push ( "--ignore-pattern=**/.next/**" ) ;
@@ -105,19 +109,19 @@ export function runTransform({
105109
106110 console . log ( `Executing command: jscodeshift ${ args . join ( " " ) } ` ) ;
107111
108- const result = execaSync ( jscodeshiftExecutable , args , {
109- stdio : "inherit" ,
110- stripFinalNewline : false ,
111- } ) ;
112+ const result = spawnSync ( jscodeshiftExecutable , args , { stdio : "inherit" } ) ;
112113
113- if ( result . failed ) {
114- throw new Error ( `jscodeshift exited with code ${ result . exitCode } ` ) ;
114+ if ( result . error ) {
115+ throw result . error ;
116+ }
117+ if ( result . status !== 0 ) {
118+ throw new Error ( `jscodeshift exited with code ${ result . status } ` ) ;
115119 }
116120}
117121
118- const TRANSFORMER_INQUIRER_CHOICES = [
122+ const TRANSFORMER_CHOICES = [
119123 {
120- name : "v5: Remove or replace deprecated props" ,
124+ title : "v5: Remove or replace deprecated props" ,
121125 value : "v5" ,
122126 } ,
123127] ;
@@ -131,101 +135,92 @@ function expandFilePathsIfNeeded(filesBeforeExpansion: string[]) {
131135 : filesBeforeExpansion ;
132136}
133137
134- const flagsSchema = {
135- force : { type : "boolean" } ,
136- dry : { type : "boolean" } ,
137- print : { type : "boolean" } ,
138- runInBand : { type : "boolean" } ,
139- jscodeshift : { type : "string" , isMultiple : true } ,
140- help : { type : "boolean" , shortFlag : "h" } ,
141- } as const satisfies AnyFlags ;
142-
143- interface PromptAnswers {
144- files ?: string ;
145- transformer ?: string ;
138+ interface ProgramOptions {
139+ force ?: boolean ;
140+ dry ?: boolean ;
141+ print ?: boolean ;
142+ runInBand ?: boolean ;
143+ jscodeshift ?: string [ ] ;
146144}
147145
148- export function run ( ) {
149- const cli = meow ( {
150- importMeta : import . meta,
151- description : "Codemods for updating chakra-react-select in applications." ,
152- help : `
153- Usage
154- $ npx crs-codemod <transform> <path> <...options>
155- transform One of the choices from https://github.com/vercel/next.js/tree/canary/packages/next-codemod
156- path Files or directory to transform. Can be a glob like pages/**.js
157- Options
158- --force Bypass Git safety checks and forcibly run codemods
159- --dry Dry run (no changes are made to files)
160- --print Print transformed files to your terminal
161- --jscodeshift (Advanced) Pass options directly to jscodeshift
162- ` ,
163- flags : flagsSchema ,
164- } ) ;
165-
166- if ( ! cli . flags . dry ) {
167- checkGitStatus ( ! ! cli . flags . force ) ;
146+ export async function run ( ) {
147+ const program = new Command ( )
148+ . description ( "Codemods for updating chakra-react-select in applications." )
149+ . argument ( "[transform]" , "codemod transform to apply" )
150+ . argument ( "[path]" , "files or directory to transform (supports globs)" )
151+ . option ( "--force" , "bypass Git safety checks and forcibly run codemods" )
152+ . option ( "--dry" , "dry run (no changes are made to files)" )
153+ . option ( "--print" , "print transformed files to your terminal" )
154+ . option (
155+ "--run-in-band" ,
156+ "run in a single process (slower but useful for debugging)"
157+ )
158+ . option (
159+ "--jscodeshift <options...>" ,
160+ "(advanced) pass options directly to jscodeshift"
161+ )
162+ . parse ( process . argv ) ;
163+
164+ const opts = program . opts < ProgramOptions > ( ) ;
165+ const [ inputTransform , inputPath ] = program . args ;
166+
167+ if ( ! opts . dry ) {
168+ checkGitStatus ( ! ! opts . force ) ;
168169 }
169170
170171 if (
171- cli . input [ 0 ] &&
172- ! TRANSFORMER_INQUIRER_CHOICES . find ( ( x ) => x . value === cli . input [ 0 ] )
172+ inputTransform &&
173+ ! TRANSFORMER_CHOICES . find ( ( x ) => x . value === inputTransform )
173174 ) {
174175 console . error ( "Invalid transform choice, pick one of:" ) ;
175- console . error (
176- TRANSFORMER_INQUIRER_CHOICES . map ( ( x ) => `- ${ x . value } ` ) . join ( "\n" )
177- ) ;
176+ console . error ( TRANSFORMER_CHOICES . map ( ( x ) => `- ${ x . value } ` ) . join ( "\n" ) ) ;
178177 process . exit ( 1 ) ;
179178 }
180179
181- const questions : DistinctQuestion < PromptAnswers > [ ] = [
182- {
183- type : "input" ,
184- name : "files" ,
185- message : "On which files or directory should the codemods be applied?" ,
186- when : ! cli . input [ 1 ] ,
187- default : "." ,
188- filter : ( files : string ) => files . trim ( ) ,
189- } ,
190- {
191- type : "select" ,
192- name : "transformer" ,
193- message : "Which transform would you like to apply?" ,
194- when : ! cli . input [ 0 ] ,
195- pageSize : TRANSFORMER_INQUIRER_CHOICES . length ,
196- choices : TRANSFORMER_INQUIRER_CHOICES ,
197- } ,
198- ] ;
199-
200- inquirer . prompt < PromptAnswers > ( questions ) . then ( ( answers ) => {
201- const { files, transformer } = answers ;
202-
203- const filesBeforeExpansion = cli . input [ 1 ] || files ;
204- if ( ! filesBeforeExpansion ) {
205- console . log ( "No files or directory provided." ) ;
206- return null ;
207- }
180+ const answers = await prompts (
181+ [
182+ {
183+ type : inputPath ? null : "text" ,
184+ name : "files" ,
185+ message : "On which files or directory should the codemods be applied?" ,
186+ initial : "." ,
187+ format : ( val : string ) => val . trim ( ) ,
188+ } ,
189+ {
190+ type : inputTransform ? null : "select" ,
191+ name : "transformer" ,
192+ message : "Which transform would you like to apply?" ,
193+ choices : TRANSFORMER_CHOICES ,
194+ } ,
195+ ] ,
196+ { onCancel : ( ) => process . exit ( 1 ) }
197+ ) ;
208198
209- const filesExpanded = expandFilePathsIfNeeded ( [ filesBeforeExpansion ] ) ;
199+ const filesBeforeExpansion = inputPath ?? answers . files ;
200+ if ( ! filesBeforeExpansion ) {
201+ console . log ( "No files or directory provided." ) ;
202+ return ;
203+ }
210204
211- const selectedTransformer = cli . input [ 0 ] || transformer ;
212- if ( ! selectedTransformer ) {
213- console . log ( "No transformer selected." ) ;
214- return null ;
215- }
205+ const selectedTransformer = inputTransform ?? answers . transformer ;
206+ if ( ! selectedTransformer ) {
207+ console . log ( "No transformer selected." ) ;
208+ return ;
209+ }
216210
217- if ( ! filesExpanded . length ) {
218- console . log ( `No files found matching ${ filesBeforeExpansion } ` ) ;
219- return null ;
220- }
211+ const filesExpanded = expandFilePathsIfNeeded ( [ filesBeforeExpansion ] ) ;
221212
222- return runTransform ( {
223- files : filesExpanded ,
224- transformer : selectedTransformer ,
225- dry : cli . flags . dry ,
226- print : cli . flags . print ,
227- runInBand : cli . flags . runInBand ,
228- jscodeshift : cli . flags . jscodeshift ,
229- } ) ;
213+ if ( ! filesExpanded . length ) {
214+ console . log ( `No files found matching ${ filesBeforeExpansion } ` ) ;
215+ return ;
216+ }
217+
218+ runTransform ( {
219+ files : filesExpanded ,
220+ transformer : selectedTransformer ,
221+ dry : opts . dry ,
222+ print : opts . print ,
223+ runInBand : opts . runInBand ,
224+ jscodeshift : opts . jscodeshift ,
230225 } ) ;
231226}
0 commit comments