Код

const fs = require('fs')
const path = require('path')
const readline = require('readline')

const rl = readline.createInterface({
	input: process.stdin,
	output: process.stdout
})

// Хэлпер для обработки ввода от пользователя в терминале
const askQuestion = query => {
	return new Promise(resolve => rl.question(query, resolve))
}

// Функция для получения пути к директории компонента
const getComponentDir = (componentName) => path.join(process.cwd(), componentName)

// Функция для создания файла стилей
const createStylesFile = ({ componentDir, componentName }) => {
	const content = `.root {}`
	const filePath = path.join(componentDir, `${componentName}.module.scss`)

	fs.writeFileSync(filePath, content)
}

// Функция для создания файла типов
const createTypesFile = ({ componentDir, componentName }) => {
	const typesContent = `export interface ${componentName}Props {}`
	const filePath = path.join(componentDir, `${componentName}.types.ts`)

	fs.writeFileSync(filePath, typesContent)
}

// Функция для создания основного файла компонента
const createComponentFile = ({ componentDir, componentName, needStyle, needTypes }) => {
	const componentContent = []
	componentContent.push("import React from 'react'")
	if (needStyle) {
		componentContent.push(`import styles from './${componentName}.module.scss'`)
	}

	if (needTypes) {
		componentContent.push(`import { ${componentName}Props } from './${componentName}.types.ts'`)
	}

	componentContent.push(``)
	if (needTypes) {
		componentContent.push(
			`export const ${componentName} = (props: ${componentName}Props) => {`
		)
	} else {
		componentContent.push(`export const ${componentName} = () => {`)
	}

	if (needStyle) {
		componentContent.push(
			`  return <div className={styles.root}>${componentName}</div>`
		)
	} else {
		componentContent.push(`  return <div>${componentName}</div>`)
	}

	componentContent.push(`}`)
	componentContent.push(``)

	const filePath = path.join(componentDir, `${componentName}.tsx`)
	fs.writeFileSync(
		filePath,
		componentContent.join('\\n')
	)
}

// Основная функция для генерации компонента
const createIndexFile = ({ componentDir, componentName, needTypes }) => {
	const componentContent = []
	componentContent.push(`export { ${componentName} } from './${componentName}'`)
	if (needTypes) {
		componentContent.push(
			`export type { ${componentName}Props } from './${componentName}.types.ts'`
		)
	}
	componentContent.push(``)

	const filePath = path.join(componentDir, 'index.ts')
	fs.writeFileSync(
		filePath,
		componentContent.join('\\n')
	)
}

// Основа
async function generateComponent() {
	let componentName = await askQuestion('Component name? ')

	// Валидация имени компонента
	while (!componentName) {
		console.error('Component name cannot be empty.')
		componentName = await askQuestion('Component name? ')
	}

	const needStyle = await askQuestion('Need style file? (y/n) ').then(
		res => res.toLowerCase() === 'y'
	)
	const needTypes = await askQuestion('Need types file? (y/n) ').then(
		res => res.toLowerCase() === 'y'
	)

	const componentDir = getComponentDir(componentName)
	// Валидация папки
	if (fs.existsSync(componentDir)) {
		throw new Error(
			`A directory with the name "${componentName}" already exists.`
		)
	}

	fs.mkdirSync(componentDir)

	createComponentFile({
		componentDir,
		componentName,
		needStyle,
		needTypes
	})

	if (needStyle) {
		createStylesFile({ componentDir, componentName })
	}

	if (needTypes) {
		createTypesFile({ componentName, componentDir })
	}

	createIndexFile({ componentDir, componentName, needTypes })

	console.log(
		'\\x1b[32m%s\\x1b[0m',
		`Component "${componentName}" created successfully.`
	)
	rl.close()
}

// Триггер, запускающий генерацию компонента
generateComponent().catch(err => {
	console.error('An error occurred:', err)
	rl.close()
})