Last active
February 4, 2021 21:18
-
-
Save fatso83/80bba191905b91f8f7f59ea94aa949a0 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Rename kebab-case files to PascalCase and vice versa | |
---------------------------------------------------- | |
- Check the `require()` calls for what to `npm install` | |
- If you need to modify something else than `*.js` files, just modify the `find` command somewhat |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env node | |
/* | |
* Rename kebab-case files into PascalCase files and update references | |
* | |
* Basic working: | |
* 1. Find all kebab case files | |
* 2. Rename them | |
* 3. Use the `git grep` to get all filenames with indexed hits of the old file name | |
* 4. Loop through the hits and update | |
*/ | |
const argv = require('yargs').argv | |
const { isEmpty, flowRight } = require('lodash') | |
const { promisify } = require('util') | |
const fs = require('fs') | |
const cp = require('child_process') | |
const { basename } = require('path') | |
const exec = promisify(cp.exec) | |
const readFile = promisify(fs.readFile) | |
const writeFile = promisify(fs.writeFile) | |
const moveFile = promisify(fs.rename) | |
const info = require('debug')('info') | |
const usage = ` | |
USAGE: rename-kebab --dir src --dir test --dir some-other | |
Will rename all kebab-case files to PascalCase and update references in the mentioned directories | |
` | |
let dirs = '' | |
if (isEmpty(argv.dir)) { | |
// eslint-disable-next-line no-console | |
console.error(usage) | |
process.exit(1) | |
} | |
if (!Array.isArray(argv.dir)) { | |
dirs = [argv.dir] | |
} else { | |
dirs = argv.dir | |
} | |
async function main() { | |
const kebabs = await execAndParseList(`find ${dirs.join(' ')} -name '*-*.js' -type f `) | |
const nonPascals = await execAndParseList(`find test/ src/ -regex '.*/[a-z]\\w*\\.js' -type f`) | |
const filesToRename = kebabs.concat(nonPascals) | |
const pascalify = flowRight(fromKebabToCamel, fromCamelToPascal) | |
for (const fullKebabPath of filesToRename) { | |
const oldNameWithoutExtension = '/' + basename(fullKebabPath, '.js') + "'" | |
const newName = pascalify(basename(fullKebabPath)) | |
const newNameWithoutExtension = '/' + basename(newName, '.js') + "'" | |
const filesWithReferences = await execAndParseList(`grep -r -l "${oldNameWithoutExtension}" ${dirs.join(' ')}`) | |
info(`${oldNameWithoutExtension} is referenced by:\n${filesWithReferences.join('\n')}`) | |
await moveFile(fullKebabPath, fullKebabPath.replace(oldNameWithoutExtension, newNameWithoutExtension)) | |
for (const file of filesWithReferences) { | |
info(`replacing contents of ${file}`) | |
const buffer = await readFile(file) | |
const newFileContent = buffer | |
.toString() | |
.replace(new RegExp(oldNameWithoutExtension, 'm'), newNameWithoutExtension) | |
await writeFile(file, newFileContent) | |
} | |
} | |
} | |
function fromCamelToPascal(camel) { | |
return camel.replace(/^(.)/, (_, char) => char.toUpperCase()) | |
} | |
function fromKebabToCamel(kebab) { | |
return kebab.replace(/\b-([a-z])/g, (_, char) => char.toUpperCase()) | |
} | |
async function execAndParseList(cmd) { | |
const tmp = await exec(cmd).catch((_) => ({ stdout: '' })) | |
return tmp.stdout.split('\n').filter((e) => e) | |
} | |
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env node | |
/* | |
* Rename kebab-case files into PascalCase files and update references | |
* | |
* Basic working: | |
* 1. Find all kebab case files | |
* 2. Rename them | |
* 3. Use the `git grep` to get all filenames with indexed hits of the old file name | |
* 4. Loop through the hits and update | |
*/ | |
const { argv } = require('yargs') | |
const { isEmpty } = require('lodash') | |
const { promisify } = require('util') | |
const fs = require('fs') | |
const cp = require('child_process') | |
const { basename } = require('path') | |
const exec = promisify(cp.exec) | |
const readFile = promisify(fs.readFile) | |
const writeFile = promisify(fs.writeFile) | |
const moveFile = promisify(fs.rename) | |
const info = require('debug')('info') | |
const test = require('debug')('test') | |
const usage = ` | |
USAGE: rename-pascals --dir src --dir test --dir some-other | |
Will rename all PascalCase to kebab-case and update references in the mentioned directories | |
` | |
let dirs = '' | |
if (isEmpty(argv.dir)) { | |
// eslint-disable-next-line no-console | |
console.error(usage) | |
process.exit(1) | |
} | |
if (!Array.isArray(argv.dir)) { | |
dirs = [argv.dir] | |
} else { | |
dirs = argv.dir | |
} | |
const excludeRegex = argv.exclude | |
async function main() { | |
const pascals = await execAndParseList(`find ${dirs.join(' ')} -regex '.*/[A-Z]\\w*\\.\\(test\\.\\)?js' -type f `) | |
const filesToRename = excludeRegex ? pascals.filter((f) => !f.match(excludeRegex)) : pascals | |
for (const fullPath of filesToRename) { | |
const oldNameWithoutExtension = basename(fullPath, '.js') | |
const tmp = basename(fullPath) | |
info(tmp) | |
const newNameWithoutExtension = fromPascalToKebab(basename(tmp, '.js')) | |
info(newNameWithoutExtension) | |
const oldRegExp = '/' + oldNameWithoutExtension | |
const newReplacement = '/' + newNameWithoutExtension | |
const filesWithReferences = await execAndParseList(`grep -r -l "${oldRegExp}" ${dirs.join(' ')}`) | |
info(`${oldNameWithoutExtension} is referenced by:\n${filesWithReferences.join('\n')}`) | |
info(`moveFile(${fullPath}, ${fullPath.replace(oldNameWithoutExtension, newNameWithoutExtension)}`) | |
await moveFile(fullPath, fullPath.replace(oldNameWithoutExtension, newNameWithoutExtension)) | |
for (const file of filesWithReferences) { | |
info(`replacing contents of ${file}`) | |
const buffer = await readFile(file) | |
const newFileContent = buffer.toString().replace(new RegExp(oldRegExp, 'm'), newReplacement) | |
await writeFile(file, newFileContent) | |
} | |
} | |
} | |
async function execAndParseList(cmd) { | |
const tmp = await exec(cmd).catch((_) => ({ stdout: '' })) | |
return tmp.stdout.split('\n').filter((e) => e) | |
} | |
function fromPascalToKebab(pascal) { | |
const matches = pascal.match(/[A-Z][a-z]+/g) | |
if (!matches) { | |
return pascal | |
} | |
let first = true | |
let kebab = '' | |
for (const part of matches) { | |
if (first) { | |
first = false | |
kebab = part.toLowerCase() | |
continue | |
} | |
kebab += `-${part.toLowerCase()}` | |
} | |
if (pascal.match('\\.test')) { | |
kebab += '.test' | |
} | |
return kebab | |
} | |
test(fromPascalToKebab('App')) | |
test(fromPascalToKebab('MyApp')) | |
test(fromPascalToKebab('MyLargeApp')) | |
test(fromPascalToKebab('MyLargeApp')) | |
test(fromPascalToKebab('MyLargeApp.test')) | |
test(fromPascalToKebab('foo.test')) | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment