| name | automation-scripts-generator |
| description | Generate automation scripts for component creation, bulk operations, code transformation, project scaffolding, and custom CLI tools for UI library development workflows |
| allowed-tools | Read, Write, Edit, Bash, Glob, Grep, Task |
Automation Scripts Generator
Expert skill for creating automation scripts and CLI tools for UI library development. Specializes in component generators, bulk operations, code transformers, project scaffolding, and custom development workflows.
Core Capabilities
1. Component Generation Scripts
- New Component: Generate complete component with tests, styles, docs
- Variant Generator: Create component variants automatically
- Bulk Creation: Generate multiple components at once
- Template Customization: Configurable component templates
- File Organization: Auto-organize files in correct structure
- Index Updates: Auto-update barrel exports
2. Code Transformation
- Refactoring Scripts: Automated code refactoring
- Migration Tools: Migrate between patterns/libraries
- Import Organizer: Sort and clean imports
- Props Transformer: Convert prop patterns
- Type Generator: Generate TypeScript types from data
- Style Converter: Convert CSS to different formats
3. Bulk Operations
- Mass Rename: Rename files/components in bulk
- Batch Update: Update props across components
- Global Replace: Smart search and replace
- Delete Unused: Find and remove unused code
- Add Feature: Add feature to multiple components
- Update Dependencies: Batch dependency updates
4. Project Scaffolding
- New Project: Initialize complete UI library
- Documentation Site: Set up Storybook/docs site
- Testing Setup: Configure testing infrastructure
- CI/CD Pipeline: Set up GitHub Actions
- Package Configuration: Set up build and publish
- Monorepo Setup: Configure Turborepo/Nx
5. CLI Tools
- Interactive Prompts: User-friendly CLI interface
- Command Framework: Build custom commands
- Configuration: Load/save preferences
- Validation: Input validation and error handling
- Progress Indicators: Show progress for long operations
- Logging: Structured logging and debugging
6. Quality Automation
- Linting Scripts: Auto-fix lint issues
- Format All: Format entire codebase
- Type Check: Run TypeScript checks
- Test Runner: Execute test suites
- Coverage Reports: Generate coverage analysis
- Performance Audit: Analyze bundle sizes
Workflow
Phase 1: Script Planning
Identify Task
- What needs automation?
- How often is it done?
- What's the manual process?
- What can go wrong?
Design Solution
- Command interface?
- Input parameters?
- Output format?
- Error handling?
Choose Tools
- Node.js script?
- Shell script?
- CLI framework?
- Dependencies needed?
Phase 2: Implementation
Build Core Logic
- File operations
- Code generation
- Validation
- Error handling
Add CLI Interface
- Argument parsing
- Interactive prompts
- Progress indicators
- Output formatting
Test Thoroughly
- Happy path
- Edge cases
- Error scenarios
- Dry run mode
Phase 3: Integration
Document Script
- Usage instructions
- Examples
- Options reference
- Troubleshooting
Add to Workflow
- npm scripts
- package.json
- CI/CD pipeline
- Developer docs
Optimize
- Performance
- Error messages
- User experience
- Logging
Script Templates
Component Generator (Node.js)
#!/usr/bin/env node
// scripts/generate-component.ts
import fs from 'fs/promises'
import path from 'path'
import { prompts } from 'prompts'
import chalk from 'chalk'
interface ComponentOptions {
name: string
type: 'basic' | 'compound' | 'polymorphic'
withTests: boolean
withStories: boolean
withDocs: boolean
}
async function generateComponent(options: ComponentOptions) {
const { name, type, withTests, withStories, withDocs } = options
console.log(chalk.blue(`\nš Generating ${type} component: ${name}\n`))
const componentDir = path.join(process.cwd(), 'src', 'components', name)
// Create directory
await fs.mkdir(componentDir, { recursive: true })
// Generate component file
const componentCode = generateComponentCode(name, type)
await fs.writeFile(path.join(componentDir, `${name}.tsx`), componentCode)
console.log(chalk.green(`ā Created ${name}.tsx`))
// Generate types file
const typesCode = generateTypesCode(name)
await fs.writeFile(path.join(componentDir, `${name}.types.ts`), typesCode)
console.log(chalk.green(`ā Created ${name}.types.ts`))
// Generate tests
if (withTests) {
const testCode = generateTestCode(name)
await fs.writeFile(path.join(componentDir, `${name}.test.tsx`), testCode)
console.log(chalk.green(`ā Created ${name}.test.tsx`))
}
// Generate Storybook story
if (withStories) {
const storyCode = generateStoryCode(name)
await fs.writeFile(path.join(componentDir, `${name}.stories.tsx`), storyCode)
console.log(chalk.green(`ā Created ${name}.stories.tsx`))
}
// Generate README
if (withDocs) {
const readmeCode = generateReadmeCode(name)
await fs.writeFile(path.join(componentDir, 'README.md'), readmeCode)
console.log(chalk.green(`ā Created README.md`))
}
// Generate index file
const indexCode = generateIndexCode(name)
await fs.writeFile(path.join(componentDir, 'index.ts'), indexCode)
console.log(chalk.green(`ā Created index.ts`))
// Update barrel export
await updateBarrelExport(name)
console.log(chalk.green(`ā Updated src/components/index.ts`))
console.log(chalk.green.bold(`\n⨠Component ${name} generated successfully!\n`))
}
function generateComponentCode(name: string, type: string): string {
const templates = {
basic: `import React from 'react'
import { ${name}Props } from './${name}.types'
export function ${name}({ children, ...props }: ${name}Props) {
return (
<div {...props}>
{children}
</div>
)
}`,
compound: `import React, { createContext, useContext } from 'react'
import { ${name}Props, ${name}ContextValue } from './${name}.types'
const ${name}Context = createContext<${name}ContextValue | undefined>(undefined)
export function ${name}({ children, ...props }: ${name}Props) {
const value: ${name}ContextValue = {
// Add context value here
}
return (
<${name}Context.Provider value={value}>
<div {...props}>{children}</div>
</${name}Context.Provider>
)
}
export function use${name}() {
const context = useContext(${name}Context)
if (!context) {
throw new Error('use${name} must be used within ${name}')
}
return context
}
${name}.Item = function ${name}Item({ children }: { children: React.ReactNode }) {
const context = use${name}()
return <div>{children}</div>
}`,
polymorphic: `import React from 'react'
import { ${name}Props } from './${name}.types'
export function ${name}<C extends React.ElementType = 'div'>({
as,
children,
...props
}: ${name}Props<C>) {
const Component = as || 'div'
return <Component {...props}>{children}</Component>
}`,
}
return templates[type] || templates.basic
}
function generateTypesCode(name: string): string {
return `import React from 'react'
export interface ${name}Props extends React.HTMLAttributes<HTMLDivElement> {
children?: React.ReactNode
// Add your props here
}
export interface ${name}ContextValue {
// Add context value types here
}`
}
function generateTestCode(name: string): string {
return `import { render, screen } from '@testing-library/react'
import { ${name} } from './${name}'
describe('${name}', () => {
it('renders children', () => {
render(<${name}>Hello World</${name}>)
expect(screen.getByText('Hello World')).toBeInTheDocument()
})
})`
}
function generateStoryCode(name: string): string {
return `import type { Meta, StoryObj } from '@storybook/react'
import { ${name} } from './${name}'
const meta: Meta<typeof ${name}> = {
title: 'Components/${name}',
component: ${name},
tags: ['autodocs'],
}
export default meta
type Story = StoryObj<typeof ${name}>
export const Default: Story = {
args: {
children: '${name} content',
},
}`
}
function generateReadmeCode(name: string): string {
return `# ${name}
## Usage
\`\`\`tsx
import { ${name} } from '@your-library/components'
function App() {
return (
<${name}>
Content here
</${name}>
)
}
\`\`\`
## Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| children | ReactNode | - | The content |
## Examples
### Basic Usage
\`\`\`tsx
<${name}>Hello World</${name}>
\`\`\`
`
}
function generateIndexCode(name: string): string {
return `export { ${name} } from './${name}'
export type { ${name}Props } from './${name}.types'`
}
async function updateBarrelExport(name: string) {
const indexPath = path.join(process.cwd(), 'src', 'components', 'index.ts')
try {
let content = await fs.readFile(indexPath, 'utf-8')
const exportLine = `export * from './${name}'\n`
// Check if export already exists
if (!content.includes(exportLine)) {
// Add export in alphabetical order
const exports = content.split('\n').filter(line => line.startsWith('export'))
exports.push(exportLine.trim())
exports.sort()
content = exports.join('\n') + '\n'
await fs.writeFile(indexPath, content)
}
} catch (error) {
// If index doesn't exist, create it
await fs.writeFile(indexPath, `export * from './${name}'\n`)
}
}
// CLI Interface
async function main() {
console.log(chalk.cyan.bold('\nš¦ Component Generator\n'))
const response = await prompts([
{
type: 'text',
name: 'name',
message: 'Component name (PascalCase):',
validate: (value) =>
/^[A-Z][a-zA-Z0-9]*$/.test(value) || 'Must be PascalCase (e.g., Button)',
},
{
type: 'select',
name: 'type',
message: 'Component type:',
choices: [
{ title: 'Basic', value: 'basic' },
{ title: 'Compound', value: 'compound' },
{ title: 'Polymorphic', value: 'polymorphic' },
],
},
{
type: 'confirm',
name: 'withTests',
message: 'Generate tests?',
initial: true,
},
{
type: 'confirm',
name: 'withStories',
message: 'Generate Storybook story?',
initial: true,
},
{
type: 'confirm',
name: 'withDocs',
message: 'Generate README?',
initial: true,
},
])
if (!response.name) {
console.log(chalk.red('\nā Cancelled\n'))
process.exit(0)
}
try {
await generateComponent(response as ComponentOptions)
} catch (error) {
console.error(chalk.red('\nā Error generating component:'), error)
process.exit(1)
}
}
main()
Bulk Rename Script
#!/bin/bash
# scripts/bulk-rename.sh
# Bulk rename components
# Usage: ./scripts/bulk-rename.sh old-pattern new-pattern
set -e
OLD_PATTERN=$1
NEW_PATTERN=$2
if [ -z "$OLD_PATTERN" ] || [ -z "$NEW_PATTERN" ]; then
echo "Usage: ./scripts/bulk-rename.sh old-pattern new-pattern"
echo "Example: ./scripts/bulk-rename.sh UIButton Button"
exit 1
fi
echo "š Renaming $OLD_PATTERN ā $NEW_PATTERN"
echo ""
# Find all files containing the old pattern
FILES=$(grep -rl "$OLD_PATTERN" src/)
if [ -z "$FILES" ]; then
echo "ā No files found containing '$OLD_PATTERN'"
exit 0
fi
echo "Files to update:"
echo "$FILES"
echo ""
read -p "Continue? (y/n) " -n 1 -r
echo ""
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "ā Cancelled"
exit 0
fi
# Replace in file contents
for file in $FILES; do
sed -i "" "s/$OLD_PATTERN/$NEW_PATTERN/g" "$file"
echo "ā Updated $file"
done
# Rename files
find src/ -name "*$OLD_PATTERN*" | while read file; do
new_file=$(echo "$file" | sed "s/$OLD_PATTERN/$NEW_PATTERN/g")
mv "$file" "$new_file"
echo "ā Renamed $file ā $new_file"
done
echo ""
echo "⨠Rename complete!"
Code Formatter Script
#!/usr/bin/env node
// scripts/format-all.ts
import { exec } from 'child_process'
import { promisify } from 'util'
import ora from 'ora'
import chalk from 'chalk'
const execAsync = promisify(exec)
interface FormatOptions {
fix: boolean
check: boolean
staged: boolean
}
async function formatCode(options: FormatOptions) {
const { fix, check, staged } = options
console.log(chalk.cyan.bold('\nšØ Code Formatter\n'))
// Get files to format
let files = 'src/**/*.{ts,tsx,js,jsx,css,scss,json,md}'
if (staged) {
const spinner = ora('Getting staged files...').start()
try {
const { stdout } = await execAsync('git diff --cached --name-only --diff-filter=ACMR')
files = stdout
.split('\n')
.filter((f) => /\.(ts|tsx|js|jsx|css|scss|json|md)$/.test(f))
.join(' ')
if (!files) {
spinner.succeed('No staged files to format')
return
}
spinner.succeed(`Found ${files.split(' ').length} staged files`)
} catch (error) {
spinner.fail('Failed to get staged files')
throw error
}
}
// Run Prettier
const prettierSpinner = ora('Running Prettier...').start()
try {
const prettierCmd = check
? `prettier --check ${files}`
: `prettier --write ${files}`
await execAsync(prettierCmd)
prettierSpinner.succeed('Prettier complete')
} catch (error) {
prettierSpinner.fail('Prettier found issues')
if (!fix) {
console.log(chalk.yellow('\nRun with --fix to auto-fix issues'))
}
throw error
}
// Run ESLint
const eslintSpinner = ora('Running ESLint...').start()
try {
const eslintCmd = fix
? `eslint ${files.replace(/\{.*\}/, '{ts,tsx,js,jsx}')} --fix`
: `eslint ${files.replace(/\{.*\}/, '{ts,tsx,js,jsx}')}`
await execAsync(eslintCmd)
eslintSpinner.succeed('ESLint complete')
} catch (error) {
eslintSpinner.fail('ESLint found issues')
if (!fix) {
console.log(chalk.yellow('\nRun with --fix to auto-fix issues'))
}
throw error
}
console.log(chalk.green.bold('\n⨠Formatting complete!\n'))
}
// CLI
const args = process.argv.slice(2)
const options: FormatOptions = {
fix: args.includes('--fix'),
check: args.includes('--check'),
staged: args.includes('--staged'),
}
formatCode(options).catch((error) => {
console.error(chalk.red('\nā Formatting failed\n'))
process.exit(1)
})
Migration Script
#!/usr/bin/env node
// scripts/migrate-to-tailwind.ts
import fs from 'fs/promises'
import path from 'path'
import { glob } from 'glob'
import chalk from 'chalk'
// CSS to Tailwind class mappings
const cssToTailwind: Record<string, string> = {
'display: flex': 'flex',
'flex-direction: column': 'flex-col',
'justify-content: center': 'justify-center',
'align-items: center': 'items-center',
'padding: 1rem': 'p-4',
'margin: 1rem': 'm-4',
'background-color: #3b82f6': 'bg-blue-500',
'color: white': 'text-white',
'font-weight: bold': 'font-bold',
'border-radius: 0.5rem': 'rounded-lg',
}
async function migrateToTailwind() {
console.log(chalk.cyan.bold('\nšØ Migrating to Tailwind CSS\n'))
// Find all component files
const files = await glob('src/components/**/*.tsx')
let totalChanges = 0
for (const file of files) {
let content = await fs.readFile(file, 'utf-8')
let changes = 0
// Find style objects
const styleRegex = /style=\{\{([^}]+)\}\}/g
const matches = content.matchAll(styleRegex)
for (const match of matches) {
const styleContent = match[1]
const classes: string[] = []
// Convert each CSS property
for (const [css, tailwind] of Object.entries(cssToTailwind)) {
if (styleContent.includes(css)) {
classes.push(tailwind)
changes++
}
}
if (classes.length > 0) {
// Replace style with className
const replacement = `className="${classes.join(' ')}"`
content = content.replace(match[0], replacement)
}
}
if (changes > 0) {
await fs.writeFile(file, content)
console.log(chalk.green(`ā ${file} (${changes} changes)`))
totalChanges += changes
}
}
console.log(chalk.green.bold(`\n⨠Migration complete! (${totalChanges} total changes)\n`))
}
migrateToTailwind().catch((error) => {
console.error(chalk.red('\nā Migration failed:'), error)
process.exit(1)
})
Best Practices
Script Design
- Single Responsibility: One script, one task
- Idempotent: Safe to run multiple times
- Dry Run: Preview changes before applying
- Validation: Validate inputs and state
- Error Handling: Graceful error messages
CLI UX
- Clear Messages: What's happening and why
- Progress Indicators: Show progress for long tasks
- Confirmation Prompts: Ask before destructive actions
- Colorized Output: Use colors meaningfully
- Help Text: Always provide --help
Code Quality
- TypeScript: Type-safe scripts
- Error Recovery: Handle failures gracefully
- Logging: Log important operations
- Testing: Test scripts with various inputs
- Documentation: Document usage and options
Performance
- Parallel Operations: Run independent tasks concurrently
- Caching: Cache expensive operations
- Incremental: Process only changed files
- Streaming: Stream large file operations
- Debouncing: Avoid duplicate operations
When to Use This Skill
Activate this skill when you need to:
- Generate new components with boilerplate
- Create CLI tools for developers
- Automate repetitive tasks
- Migrate code between patterns
- Scaffold new projects
- Bulk update code across files
- Transform code automatically
- Set up automation workflows
- Build custom dev tools
- Optimize development workflow
Output Format
When creating automation scripts, provide:
- Complete Script: Production-ready code
- Installation Instructions: Dependencies and setup
- Usage Guide: How to run the script
- Options Reference: All available flags/options
- Examples: Common use cases
- Error Handling: How errors are reported
Always build scripts that save time, prevent errors, and improve developer experience.