Skip to content

Instantly share code, notes, and snippets.

@lensanag
Created June 10, 2023 06:14
Show Gist options
  • Save lensanag/18187ad37c0013d483a0d31bca3cde2d to your computer and use it in GitHub Desktop.
Save lensanag/18187ad37c0013d483a0d31bca3cde2d to your computer and use it in GitHub Desktop.
automate creation of react components, you can easily update file templates to your needs 😎
/*
// include script in package.json the line number 6
{
"scripts": {
"mk:component": "node scripts/component-builder.js"
}
}
// then use:
npm run mk:component MyComponent [OPTIONS]
npm run mk:component --help
*/
import fs from 'fs'
/**
* body definition of jsx component
* @param {string} name
* @returns
*/
const componentTag = (name) => `import styles from './${name}.module.css';
export default function ${name} () {
return (<>
<span className={styles.${name}}>${name} needs to be implement πŸ˜…!</span>
</>);
};
export { ${name} };
`
/**
* body definition of css component styles
* @param {string} name
* @returns
*/
const stylesTag = (name) => `.${name} {
font-weight: bold;
font-style: italic;
color: red;
}
`
/**
* body definition of index file to export component
* @param {string} name
* @returns
*/
const indexTag = (name) => `import ${name} from "./${name}";
export default ${name};
export { ${name} };
`
/**
*
* @param {string} name
* @param {boolean} includeDir
* @param {string?} differentPath
* @returns
*/
const Work = (name, includeDir, differentPath = 'components') => {
const path = `./src/${differentPath}` + (!includeDir ? '' : '/' + name)
const Files = [
[`${path}/${name}.jsx`, componentTag(name)],
[`${path}/${name}.module.css`, stylesTag(name)],
[`${path}/index.js`, indexTag(name)],
]
if (!includeDir) {
Files.pop()
}
return [path, Files]
}
/**
* prints multiple strings to console with an optional callback formatter
* @param {(string) => string} callback
* @param {[string]} strings
*/
const GenericPrintMultiple = (strings, callback = (value) => value) => {
strings.forEach(string => {
console.log(callback(string))
})
}
const START_MESSAGE = [
'====================================',
' React Component Builder',
'====================================',
]
const OPTIONS = [
' OPTIONS:',
' --dir flag to create component directory where to keep component files 😏 (not created by default, optional)',
' --preserve flag to preserve previous component directory and files 😊',
' --wipe flag to remove previous component directory 😧',
' --overwrite flag to overwrite existing files (works with --preserve flag) 😐',
]
const EXAMPLES = [
' EXAMPLES: ',
' MyComponent --dir',
' MyComponent:views/bussines/final',
' MyComponent:views/bussines/final --preserve --dir',
' OtherComponent:pages/public --preserve --overwrite',
' AnotherComponent:components/shared --wipe --dir',
]
const HELP = [
'',
'HELP:',
'',
...OPTIONS,
'',
...EXAMPLES,
'',
]
GenericPrintMultiple(START_MESSAGE)
if (process.argv.includes('--help') || process.argv.includes('-h')) {
GenericPrintMultiple(HELP)
process.exit(0)
}
const args = process.argv.slice(2)
if (args.length === 0) {
console.log('Please provide a component name')
process.exit(1)
}
const firstArg = args[0]
const wipe = args.includes('--wipe')
const preserve = args.includes('--preserve')
const overwrite = args.includes('--overwrite')
const includeDir = args.includes('--dir')
if (preserve && wipe) {
console.log('You can use only one of --preserve or --wipe flags at time')
process.exit(1)
}
if (firstArg.length === 0) {
console.log('Please provide a component name')
process.exit(1)
}
if (!/^[A-Z]{1,1}[a-zA-Z0-9]+:{0,1}[a-zA-Z0-9]+[a-zA-Z0-9/]+[a-zA-Z0-9]+$/.test(firstArg) || firstArg.split('/').includes('')) {
console.log('Please provide a valid component name in PascalCase format')
process.exit(1)
}
const [componentName, rootPath] = firstArg.split(':')
if (!includeDir && wipe) {
console.log('You cannot use --wipe flag without --dir flag to avoid unintended directory deletion 😎')
process.exit(1)
}
console.log('Starting component creation...')
const [componentPath, files] = Work(componentName, includeDir, rootPath)
if (includeDir) {
if (fs.existsSync(componentPath) && fs.statSync(componentPath).isDirectory()) {
if (wipe) {
console.log('You choosse remove previous component directory πŸ₯Ά')
fs.rmSync(componentPath, { recursive: true });
fs.mkdirSync(componentPath);
} else {
if (preserve) {
console.log('You choosse preserve previous component directory 😊')
} else {
GenericPrintMultiple([
'Directory already exist 🀨',
'You can use:',
...OPTIONS.slice(1),
...files.map(([file,]) => file),
'Or call the command with -h or --help for examples!'
])
process.exit(1)
}
}
} else {
fs.mkdirSync(componentPath, { recursive: true });
}
}
if (files.some(([file,]) => {
return fs.existsSync(file)
}) && !overwrite) {
console.log(`some files already exist in directory '${componentPath}' 🀨, use --overwrite flag to overwrite existing files that match some of:`)
GenericPrintMultiple(files.map(([file,]) => file))
process.exit(1)
}
if (overwrite) {
console.log('You choosse overwrite existing files matched πŸ₯Ά');
}
files.forEach(([file, tag]) => fs.writeFile( file, tag, () => undefined));
GenericPrintMultiple([
'',
'Component created successfully πŸŽ‰βœ¨!',
'',
`Next files were created${overwrite ? ' or overwritten' : ''}:`,
...files.map(([file,]) => file)
])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment