|
| 1 | +/** |
| 2 | + * Copyright 2015-present, Facebook, Inc. |
| 3 | + * |
| 4 | + * This source code is licensed under the MIT license found in the |
| 5 | + * LICENSE file in the root directory of this source tree. |
| 6 | + * |
| 7 | + */ |
| 8 | +// Based on https://github.com/reactjs/react-codemod/blob/dd8671c9a470a2c342b221ec903c574cf31e9f57/bin/cli.js |
| 9 | +// @hookform/codemod optional-name-of-transform optional/path/to/src [...options] |
| 10 | + |
| 11 | +const globby = require('globby'); |
| 12 | +const inquirer = require('inquirer'); |
| 13 | +const meow = require('meow'); |
| 14 | +const path = require('path'); |
| 15 | +const execa = require('execa'); |
| 16 | +const chalk = require('chalk'); |
| 17 | +const isGitClean = require('is-git-clean'); |
| 18 | + |
| 19 | +const transformerDirectory = path.join(__dirname, '../', 'transforms'); |
| 20 | +const jscodeshiftExecutable = require.resolve('.bin/jscodeshift'); |
| 21 | + |
| 22 | +function checkGitStatus(force) { |
| 23 | + let clean = false; |
| 24 | + let errorMessage = 'Unable to determine if git directory is clean'; |
| 25 | + try { |
| 26 | + clean = isGitClean.sync(process.cwd()); |
| 27 | + errorMessage = 'Git directory is not clean'; |
| 28 | + } catch (err) { |
| 29 | + if (err && err.stderr && err.stderr.indexOf('Not a git repository') >= 0) { |
| 30 | + clean = true; |
| 31 | + } |
| 32 | + } |
| 33 | + |
| 34 | + if (!clean) { |
| 35 | + if (force) { |
| 36 | + console.log(`WARNING: ${errorMessage}. Forcibly continuing.`); |
| 37 | + } else { |
| 38 | + console.log('Thank you for using @hookform/codemod!'); |
| 39 | + console.log( |
| 40 | + chalk.yellow( |
| 41 | + '\nBut before we continue, please stash or commit your git changes.' |
| 42 | + ) |
| 43 | + ); |
| 44 | + console.log( |
| 45 | + '\nYou may use the --force flag to override this safety check.' |
| 46 | + ); |
| 47 | + process.exit(1); |
| 48 | + } |
| 49 | + } |
| 50 | +} |
| 51 | + |
| 52 | +function runTransform({ files, flags, transformer }) { |
| 53 | + const transformerPath = path.join(transformerDirectory, `${transformer}.js`); |
| 54 | + |
| 55 | + let args = []; |
| 56 | + |
| 57 | + const { dry, print } = flags; |
| 58 | + |
| 59 | + if (dry) { |
| 60 | + args.push('--dry'); |
| 61 | + } |
| 62 | + if (print) { |
| 63 | + args.push('--print'); |
| 64 | + } |
| 65 | + |
| 66 | + args.push('--verbose=2'); |
| 67 | + |
| 68 | + args.push('--ignore-pattern=**/node_modules/**'); |
| 69 | + |
| 70 | + args.push('--extensions=tsx,ts,jsx,js'); |
| 71 | + args.push('--parser=tsx'); |
| 72 | + |
| 73 | + args = args.concat(['--transform', transformerPath]); |
| 74 | + |
| 75 | + if (flags.jscodeshift) { |
| 76 | + args = args.concat(flags.jscodeshift); |
| 77 | + } |
| 78 | + |
| 79 | + args = args.concat(files); |
| 80 | + |
| 81 | + console.log(`Executing command: jscodeshift ${args.join(' ')}`); |
| 82 | + |
| 83 | + const result = execa.sync(jscodeshiftExecutable, args, { |
| 84 | + stdio: 'inherit', |
| 85 | + stripEof: false |
| 86 | + }); |
| 87 | + |
| 88 | + if (result.error) { |
| 89 | + throw result.error; |
| 90 | + } |
| 91 | +} |
| 92 | + |
| 93 | +const TRANSFORMER_INQUIRER_CHOICES = [ |
| 94 | + { |
| 95 | + name: 'register-migration: Transforms register', |
| 96 | + value: 'register-migration' |
| 97 | + } |
| 98 | +]; |
| 99 | + |
| 100 | +function expandFilePathsIfNeeded(filesBeforeExpansion) { |
| 101 | + const shouldExpandFiles = filesBeforeExpansion.some((file) => |
| 102 | + file.includes('*') |
| 103 | + ); |
| 104 | + return shouldExpandFiles |
| 105 | + ? globby.sync(filesBeforeExpansion) |
| 106 | + : filesBeforeExpansion; |
| 107 | +} |
| 108 | + |
| 109 | +function run() { |
| 110 | + const cli = meow( |
| 111 | + { |
| 112 | + description: 'Codemods for updating react-hook-form apps.', |
| 113 | + help: ` |
| 114 | + Usage |
| 115 | + $ npx @hookform/codemod <transform> <path> <...options> |
| 116 | + transform One of the choices from https://github.com/react-hook-form/codemod/blob/master/README.md |
| 117 | + path Files or directory to transform. Can be a glob like src/**.js |
| 118 | + Options |
| 119 | + --force Bypass Git safety checks and forcibly run codemods |
| 120 | + --dry Dry run (no changes are made to files) |
| 121 | + --print Print transformed files to your terminal |
| 122 | + --jscodeshift (Advanced) Pass options directly to jscodeshift |
| 123 | + ` |
| 124 | + }, |
| 125 | + { |
| 126 | + boolean: ['force', 'dry', 'print', 'help'], |
| 127 | + string: ['_'], |
| 128 | + alias: { |
| 129 | + h: 'help' |
| 130 | + } |
| 131 | + } |
| 132 | + ); |
| 133 | + |
| 134 | + if (!cli.flags.dry) { |
| 135 | + checkGitStatus(cli.flags.force); |
| 136 | + } |
| 137 | + |
| 138 | + if ( |
| 139 | + cli.input[0] && |
| 140 | + !TRANSFORMER_INQUIRER_CHOICES.find((x) => x.value === cli.input[0]) |
| 141 | + ) { |
| 142 | + console.error('Invalid transform choice, pick one of:'); |
| 143 | + console.error( |
| 144 | + TRANSFORMER_INQUIRER_CHOICES.map((x) => '- ' + x.value).join('\n') |
| 145 | + ); |
| 146 | + process.exit(1); |
| 147 | + } |
| 148 | + |
| 149 | + inquirer |
| 150 | + .prompt([ |
| 151 | + { |
| 152 | + type: 'input', |
| 153 | + name: 'files', |
| 154 | + message: 'On which files or directory should the codemods be applied?', |
| 155 | + when: !cli.input[1], |
| 156 | + default: '.', |
| 157 | + // validate: () => |
| 158 | + filter: (files) => files.trim() |
| 159 | + }, |
| 160 | + { |
| 161 | + type: 'list', |
| 162 | + name: 'transformer', |
| 163 | + message: 'Which transform would you like to apply?', |
| 164 | + when: !cli.input[0], |
| 165 | + pageSize: TRANSFORMER_INQUIRER_CHOICES.length, |
| 166 | + choices: TRANSFORMER_INQUIRER_CHOICES |
| 167 | + } |
| 168 | + ]) |
| 169 | + .then((answers) => { |
| 170 | + const { files, transformer } = answers; |
| 171 | + |
| 172 | + const filesBeforeExpansion = cli.input[1] || files; |
| 173 | + const filesExpanded = expandFilePathsIfNeeded([filesBeforeExpansion]); |
| 174 | + |
| 175 | + const selectedTransformer = cli.input[0] || transformer; |
| 176 | + |
| 177 | + if (!filesExpanded.length) { |
| 178 | + console.log( |
| 179 | + `No files found matching ${filesBeforeExpansion.join(' ')}` |
| 180 | + ); |
| 181 | + return null; |
| 182 | + } |
| 183 | + |
| 184 | + return runTransform({ |
| 185 | + files: filesExpanded, |
| 186 | + flags: cli.flags, |
| 187 | + transformer: selectedTransformer |
| 188 | + }); |
| 189 | + }); |
| 190 | +} |
| 191 | + |
| 192 | +module.exports = { |
| 193 | + run: run, |
| 194 | + runTransform: runTransform, |
| 195 | + checkGitStatus: checkGitStatus, |
| 196 | + jscodeshiftExecutable: jscodeshiftExecutable, |
| 197 | + transformerDirectory: transformerDirectory |
| 198 | +}; |
0 commit comments