44 *
55 * @see {@link https://github.com/vercel/next.js/blob/dc9f30c/packages/next-codemod/bin/cli.ts }
66 */
7- import execa from "execa" ;
8- import globby from "globby" ;
9- import inquirer from "inquirer" ;
7+ import { execaSync } from "execa" ;
8+ import { globbySync } from "globby" ;
9+ import inquirer , { type DistinctQuestion } from "inquirer" ;
1010import isGitClean from "is-git-clean" ;
11- import meow from "meow" ;
12- import path from "path" ;
13- import { yellow } from "picocolors" ;
11+ import meow , { type AnyFlags } from "meow" ;
12+ import { createRequire } from "node:module" ;
13+ import path from "node:path" ;
14+ import { fileURLToPath } from "node:url" ;
15+ import pc from "picocolors" ;
1416
15- export const jscodeshiftExecutable = require . resolve ( ".bin/jscodeshift" ) ;
17+ const { yellow } = pc ;
18+
19+ const require = createRequire ( import . meta. url ) ;
20+ const __dirname = path . dirname ( fileURLToPath ( import . meta. url ) ) ;
21+
22+ export const jscodeshiftExecutable =
23+ require . resolve ( "jscodeshift/bin/jscodeshift.js" ) ;
1624export const transformerDirectory = path . join ( __dirname , "../" , "transforms" ) ;
1725
1826export function checkGitStatus ( force : boolean ) {
@@ -21,8 +29,12 @@ export function checkGitStatus(force: boolean) {
2129 try {
2230 clean = isGitClean . sync ( process . cwd ( ) ) ;
2331 errorMessage = "Git directory is not clean" ;
24- } catch ( err ) {
25- if ( err && err . stderr && err . stderr . includes ( "Not a git repository" ) ) {
32+ } catch ( err : unknown ) {
33+ const stderr =
34+ err && typeof err === "object" && "stderr" in err
35+ ? String ( ( err as { stderr : unknown } ) . stderr )
36+ : "" ;
37+ if ( stderr . includes ( "Not a git repository" ) ) {
2638 clean = true ;
2739 }
2840 }
@@ -45,12 +57,26 @@ export function checkGitStatus(force: boolean) {
4557 }
4658}
4759
48- export async function runTransform ( { files, flags, transformer } ) {
49- const transformerPath = path . join ( transformerDirectory , `${ transformer } .js` ) ;
60+ interface RunTransformOptions {
61+ files : string [ ] ;
62+ transformer : string ;
63+ dry ?: boolean ;
64+ print ?: boolean ;
65+ runInBand ?: boolean ;
66+ jscodeshift ?: readonly string [ ] ;
67+ }
5068
51- let args = [ ] ;
69+ export function runTransform ( {
70+ files,
71+ transformer,
72+ dry,
73+ print,
74+ runInBand,
75+ jscodeshift,
76+ } : RunTransformOptions ) {
77+ const transformerPath = path . join ( transformerDirectory , `${ transformer } .js` ) ;
5278
53- const { dry , print , runInBand } = flags ;
79+ const args : string [ ] = [ ] ;
5480
5581 if ( dry ) {
5682 args . push ( "--dry" ) ;
@@ -69,17 +95,17 @@ export async function runTransform({ files, flags, transformer }) {
6995
7096 args . push ( "--extensions=tsx,ts,jsx,js" ) ;
7197
72- args = args . concat ( [ "--transform" , transformerPath ] ) ;
98+ args . push ( "--transform" , transformerPath ) ;
7399
74- if ( flags . jscodeshift ) {
75- args = args . concat ( flags . jscodeshift ) ;
100+ if ( jscodeshift ) {
101+ args . push ( .. .jscodeshift ) ;
76102 }
77103
78- args = args . concat ( files ) ;
104+ args . push ( ... files ) ;
79105
80106 console . log ( `Executing command: jscodeshift ${ args . join ( " " ) } ` ) ;
81107
82- const result = execa . sync ( jscodeshiftExecutable , args , {
108+ const result = execaSync ( jscodeshiftExecutable , args , {
83109 stdio : "inherit" ,
84110 stripFinalNewline : false ,
85111 } ) ;
@@ -96,17 +122,32 @@ const TRANSFORMER_INQUIRER_CHOICES = [
96122 } ,
97123] ;
98124
99- function expandFilePathsIfNeeded ( filesBeforeExpansion ) {
125+ function expandFilePathsIfNeeded ( filesBeforeExpansion : string [ ] ) {
100126 const shouldExpandFiles = filesBeforeExpansion . some ( ( file ) =>
101127 file . includes ( "*" )
102128 ) ;
103129 return shouldExpandFiles
104- ? globby . sync ( filesBeforeExpansion )
130+ ? globbySync ( filesBeforeExpansion )
105131 : filesBeforeExpansion ;
106132}
107133
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 ;
146+ }
147+
108148export function run ( ) {
109149 const cli = meow ( {
150+ importMeta : import . meta,
110151 description : "Codemods for updating chakra-react-select in applications." ,
111152 help : `
112153 Usage
@@ -119,14 +160,8 @@ export function run() {
119160 --print Print transformed files to your terminal
120161 --jscodeshift (Advanced) Pass options directly to jscodeshift
121162 ` ,
122- flags : {
123- boolean : [ "force" , "dry" , "print" , "help" ] ,
124- string : [ "_" ] ,
125- alias : {
126- h : "help" ,
127- } ,
128- } ,
129- } as meow . Options < meow . AnyFlags > ) ;
163+ flags : flagsSchema ,
164+ } ) ;
130165
131166 if ( ! cli . flags . dry ) {
132167 checkGitStatus ( ! ! cli . flags . force ) ;
@@ -143,44 +178,54 @@ export function run() {
143178 process . exit ( 1 ) ;
144179 }
145180
146- inquirer
147- . prompt ( [
148- {
149- type : "input" ,
150- name : "files" ,
151- message : "On which files or directory should the codemods be applied?" ,
152- when : ! cli . input [ 1 ] ,
153- default : "." ,
154- filter : ( files ) => files . trim ( ) ,
155- } ,
156- {
157- type : "list" ,
158- name : "transformer" ,
159- message : "Which transform would you like to apply?" ,
160- when : ! cli . input [ 0 ] ,
161- pageSize : TRANSFORMER_INQUIRER_CHOICES . length ,
162- choices : TRANSFORMER_INQUIRER_CHOICES ,
163- } ,
164- ] )
165- . then ( ( answers ) => {
166- const { files, transformer } = answers ;
167-
168- const filesBeforeExpansion = cli . input [ 1 ] || files ;
169- const filesExpanded = expandFilePathsIfNeeded ( [ filesBeforeExpansion ] ) ;
170-
171- const selectedTransformer = cli . input [ 0 ] || transformer ;
172-
173- if ( ! filesExpanded . length ) {
174- console . log (
175- `No files found matching ${ filesBeforeExpansion . join ( " " ) } `
176- ) ;
177- return null ;
178- }
179-
180- return runTransform ( {
181- files : filesExpanded ,
182- flags : cli . flags ,
183- transformer : selectedTransformer ,
184- } ) ;
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+ }
208+
209+ const filesExpanded = expandFilePathsIfNeeded ( [ filesBeforeExpansion ] ) ;
210+
211+ const selectedTransformer = cli . input [ 0 ] || transformer ;
212+ if ( ! selectedTransformer ) {
213+ console . log ( "No transformer selected." ) ;
214+ return null ;
215+ }
216+
217+ if ( ! filesExpanded . length ) {
218+ console . log ( `No files found matching ${ filesBeforeExpansion } ` ) ;
219+ return null ;
220+ }
221+
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 ,
185229 } ) ;
230+ } ) ;
186231}
0 commit comments