Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 18:20:21 +08:00
commit bbbaf7acad
63 changed files with 38552 additions and 0 deletions

View File

@@ -0,0 +1,139 @@
#!/bin/bash
# Purpose: Analyze code complexity using ESLint
# Version: 1.0.0
# Usage: ./analyze-complexity.sh <scope> [max-complexity]
# Returns: 0 on success, 1 on error
# Dependencies: npx, eslint
set -euo pipefail
# Configuration
SCOPE="${1:-.}"
MAX_COMPLEXITY="${2:-10}"
MAX_DEPTH="${3:-3}"
MAX_LINES="${4:-50}"
MAX_PARAMS="${5:-4}"
OUTPUT_FILE="complexity-report.json"
# Colors for output
RED='\033[0;31m'
YELLOW='\033[1;33m'
GREEN='\033[0;32m'
NC='\033[0m' # No Color
# Check if scope exists
if [ ! -e "$SCOPE" ]; then
echo -e "${RED}Error: Scope does not exist: $SCOPE${NC}" >&2
exit 1
fi
echo "Analyzing complexity for: $SCOPE"
echo "Max complexity: $MAX_COMPLEXITY"
echo "Max depth: $MAX_DEPTH"
echo "Max lines per function: $MAX_LINES"
echo "Max parameters: $MAX_PARAMS"
echo ""
# Check if eslint is available
if ! command -v npx &> /dev/null; then
echo -e "${RED}Error: npx not found. Please install Node.js and npm.${NC}" >&2
exit 1
fi
# Create ESLint config for complexity analysis
ESLINT_CONFIG=$(cat <<EOF
{
"parserOptions": {
"ecmaVersion": 2020,
"sourceType": "module",
"ecmaFeatures": {
"jsx": true
}
},
"parser": "@typescript-eslint/parser",
"rules": {
"complexity": ["error", { "max": ${MAX_COMPLEXITY} }],
"max-depth": ["error", ${MAX_DEPTH}],
"max-lines-per-function": ["error", { "max": ${MAX_LINES}, "skipBlankLines": true, "skipComments": true }],
"max-params": ["error", ${MAX_PARAMS}],
"max-nested-callbacks": ["error", 3],
"max-statements": ["error", 20]
}
}
EOF
)
# Write temp config
TEMP_CONFIG=$(mktemp)
echo "$ESLINT_CONFIG" > "$TEMP_CONFIG"
# Run ESLint complexity analysis
echo "Running complexity analysis..."
npx eslint "$SCOPE" \
--ext .js,.jsx,.ts,.tsx \
--config "$TEMP_CONFIG" \
--format json \
--output-file "$OUTPUT_FILE" \
2>&1 || true
# Parse results
if [ -f "$OUTPUT_FILE" ]; then
TOTAL_FILES=$(jq 'length' "$OUTPUT_FILE")
TOTAL_WARNINGS=$(jq '[.[].warningCount] | add // 0' "$OUTPUT_FILE")
TOTAL_ERRORS=$(jq '[.[].errorCount] | add // 0' "$OUTPUT_FILE")
echo ""
echo "=== Complexity Analysis Results ==="
echo "Files analyzed: $TOTAL_FILES"
echo "Warnings: $TOTAL_WARNINGS"
echo "Errors: $TOTAL_ERRORS"
echo ""
# Show critical issues (complexity > max)
CRITICAL_ISSUES=$(jq -r '
.[] |
select(.messages | length > 0) |
.filePath as $file |
.messages[] |
select(.ruleId == "complexity" and .severity == 2) |
"\($file):\(.line):\(.column) - \(.message)"
' "$OUTPUT_FILE" | head -20)
if [ -n "$CRITICAL_ISSUES" ]; then
echo -e "${RED}Critical Complexity Issues:${NC}"
echo "$CRITICAL_ISSUES"
echo ""
fi
# Show files with most issues
echo -e "${YELLOW}Files with Most Issues:${NC}"
jq -r '
sort_by(-.errorCount - .warningCount) |
.[:5] |
.[] |
"\(.filePath): \(.errorCount) errors, \(.warningCount) warnings"
' "$OUTPUT_FILE"
echo ""
echo "Full report saved to: $OUTPUT_FILE"
# Summary
if [ "$TOTAL_ERRORS" -gt 0 ]; then
echo -e "${RED}Status: FAILED - $TOTAL_ERRORS functions exceed complexity threshold${NC}"
exit 0 # Don't fail, just report
elif [ "$TOTAL_WARNINGS" -gt 0 ]; then
echo -e "${YELLOW}Status: WARNING - $TOTAL_WARNINGS potential complexity issues${NC}"
else
echo -e "${GREEN}Status: PASSED - All functions within complexity limits${NC}"
fi
else
echo -e "${RED}Error: Failed to generate complexity report${NC}" >&2
exit 1
fi
# Cleanup
rm -f "$TEMP_CONFIG"
exit 0

View File

@@ -0,0 +1,128 @@
#!/bin/bash
# Purpose: Detect code duplication using jsinspect
# Version: 1.0.0
# Usage: ./detect-duplication.sh <scope> [threshold]
# Returns: 0 on success, 1 on error
# Dependencies: npx, jsinspect
set -euo pipefail
# Configuration
SCOPE="${1:-.}"
THRESHOLD="${2:-80}"
MIN_INSTANCES="${3:-2}"
OUTPUT_FILE="duplication-report.json"
# Colors for output
RED='\033[0;31m'
YELLOW='\033[1;33m'
GREEN='\033[0;32m'
NC='\033[0m' # No Color
# Check if scope exists
if [ ! -e "$SCOPE" ]; then
echo -e "${RED}Error: Scope does not exist: $SCOPE${NC}" >&2
exit 1
fi
echo "Detecting code duplication in: $SCOPE"
echo "Similarity threshold: ${THRESHOLD}%"
echo "Minimum instances: $MIN_INSTANCES"
echo ""
# Check if npx is available
if ! command -v npx &> /dev/null; then
echo -e "${RED}Error: npx not found. Please install Node.js and npm.${NC}" >&2
exit 1
fi
# Run jsinspect
echo "Analyzing code for duplicates..."
npx jsinspect "$SCOPE" \
--threshold "$THRESHOLD" \
--min-instances "$MIN_INSTANCES" \
--ignore "node_modules|dist|build|coverage|test|__tests__|*.spec.*|*.test.*" \
--reporter json \
> "$OUTPUT_FILE" 2>&1 || true
# Parse results
if [ -f "$OUTPUT_FILE" ]; then
# Check if output is valid JSON
if ! jq empty "$OUTPUT_FILE" 2>/dev/null; then
# Not JSON, probably text output or error
if [ -s "$OUTPUT_FILE" ]; then
echo -e "${YELLOW}Warning: Output is not JSON format${NC}"
cat "$OUTPUT_FILE"
else
echo -e "${GREEN}No duplicates found!${NC}"
echo "Duplication threshold: ${THRESHOLD}%"
echo "Status: PASSED"
rm -f "$OUTPUT_FILE"
exit 0
fi
else
# Valid JSON output
DUPLICATE_COUNT=$(jq 'length' "$OUTPUT_FILE")
if [ "$DUPLICATE_COUNT" -eq 0 ]; then
echo -e "${GREEN}No duplicates found!${NC}"
echo "Duplication threshold: ${THRESHOLD}%"
echo "Status: PASSED"
rm -f "$OUTPUT_FILE"
exit 0
fi
echo ""
echo "=== Duplication Analysis Results ==="
echo "Duplicate blocks found: $DUPLICATE_COUNT"
echo ""
# Show duplicate details
echo -e "${RED}Duplicate Code Blocks:${NC}"
echo ""
jq -r '
.[] |
"Block \(.id // "N/A"):",
" Lines: \(.lines)",
" Instances: \(.instances | length)",
" Locations:",
(.instances[] | " - \(.path):\(.lines[0])-\(.lines[1])"),
""
' "$OUTPUT_FILE" | head -100
echo ""
echo "Full report saved to: $OUTPUT_FILE"
# Calculate statistics
TOTAL_INSTANCES=$(jq '[.[].instances | length] | add' "$OUTPUT_FILE")
AVG_LINES=$(jq '[.[].lines] | add / length | floor' "$OUTPUT_FILE")
echo ""
echo "=== Statistics ==="
echo "Total duplicate instances: $TOTAL_INSTANCES"
echo "Average duplicate size: $AVG_LINES lines"
echo ""
if [ "$DUPLICATE_COUNT" -gt 10 ]; then
echo -e "${RED}Status: HIGH DUPLICATION - $DUPLICATE_COUNT blocks found${NC}"
elif [ "$DUPLICATE_COUNT" -gt 5 ]; then
echo -e "${YELLOW}Status: MODERATE DUPLICATION - $DUPLICATE_COUNT blocks found${NC}"
else
echo -e "${YELLOW}Status: LOW DUPLICATION - $DUPLICATE_COUNT blocks found${NC}"
fi
echo ""
echo "Recommendations:"
echo "1. Extract duplicate code to shared functions/components"
echo "2. Use parameterization to reduce duplication"
echo "3. Consider design patterns (Strategy, Template Method)"
fi
else
echo -e "${RED}Error: Failed to generate duplication report${NC}" >&2
exit 1
fi
exit 0

View File

@@ -0,0 +1,174 @@
#!/bin/bash
# Purpose: Verify test coverage for code being refactored
# Version: 1.0.0
# Usage: ./verify-tests.sh <scope> [min-coverage]
# Returns: 0 if coverage adequate, 1 if insufficient
# Dependencies: npm, test runner (jest/mocha/etc)
set -euo pipefail
# Configuration
SCOPE="${1:-.}"
MIN_COVERAGE="${2:-70}"
OUTPUT_FILE="coverage-report.json"
# Colors for output
RED='\033[0;31m'
YELLOW='\033[1;33m'
GREEN='\033[0;32m'
NC='\033[0m' # No Color
# Check if scope exists
if [ ! -e "$SCOPE" ]; then
echo -e "${RED}Error: Scope does not exist: $SCOPE${NC}" >&2
exit 1
fi
echo "Verifying test coverage for: $SCOPE"
echo "Minimum coverage required: ${MIN_COVERAGE}%"
echo ""
# Check if package.json exists
if [ ! -f "package.json" ]; then
echo -e "${YELLOW}Warning: No package.json found. Skipping test coverage check.${NC}"
exit 0
fi
# Check if test script exists
if ! grep -q '"test"' package.json; then
echo -e "${YELLOW}Warning: No test script found in package.json. Skipping test coverage check.${NC}"
exit 0
fi
# Run tests with coverage
echo "Running tests with coverage..."
echo ""
# Try different test runners
if npm test -- --coverage --watchAll=false --json --outputFile="$OUTPUT_FILE" 2>&1; then
TEST_RUNNER="jest"
elif npm run test:coverage 2>&1; then
TEST_RUNNER="npm"
else
echo -e "${YELLOW}Warning: Could not run tests with coverage${NC}"
echo "Make sure your test runner supports coverage reporting"
exit 0
fi
echo ""
# Try to find coverage summary
COVERAGE_SUMMARY=""
if [ -f "coverage/coverage-summary.json" ]; then
COVERAGE_SUMMARY="coverage/coverage-summary.json"
elif [ -f "coverage/lcov.info" ]; then
echo "LCOV format detected, parsing..."
# Convert lcov to summary (simplified)
COVERAGE_SUMMARY="coverage/lcov.info"
elif [ -f "$OUTPUT_FILE" ]; then
COVERAGE_SUMMARY="$OUTPUT_FILE"
fi
if [ -z "$COVERAGE_SUMMARY" ]; then
echo -e "${YELLOW}Warning: Could not find coverage report${NC}"
echo "Coverage report paths checked:"
echo " - coverage/coverage-summary.json"
echo " - coverage/lcov.info"
echo " - $OUTPUT_FILE"
exit 0
fi
# Parse coverage results
echo "=== Test Coverage Results ==="
echo ""
if [[ "$COVERAGE_SUMMARY" == *.json ]]; then
# JSON format (Jest)
if jq empty "$COVERAGE_SUMMARY" 2>/dev/null; then
# Check if it's coverage-summary.json format
if jq -e '.total' "$COVERAGE_SUMMARY" >/dev/null 2>&1; then
STATEMENTS=$(jq -r '.total.statements.pct // 0' "$COVERAGE_SUMMARY")
BRANCHES=$(jq -r '.total.branches.pct // 0' "$COVERAGE_SUMMARY")
FUNCTIONS=$(jq -r '.total.functions.pct // 0' "$COVERAGE_SUMMARY")
LINES=$(jq -r '.total.lines.pct // 0' "$COVERAGE_SUMMARY")
echo "Overall Coverage:"
echo " Statements: ${STATEMENTS}%"
echo " Branches: ${BRANCHES}%"
echo " Functions: ${FUNCTIONS}%"
echo " Lines: ${LINES}%"
echo ""
# Check if coverage meets minimum
COVERAGE_OK=true
if (( $(echo "$STATEMENTS < $MIN_COVERAGE" | bc -l) )); then
COVERAGE_OK=false
echo -e "${RED}✗ Statements coverage (${STATEMENTS}%) below minimum (${MIN_COVERAGE}%)${NC}"
else
echo -e "${GREEN}✓ Statements coverage (${STATEMENTS}%) meets minimum${NC}"
fi
if (( $(echo "$BRANCHES < $MIN_COVERAGE" | bc -l) )); then
COVERAGE_OK=false
echo -e "${RED}✗ Branches coverage (${BRANCHES}%) below minimum (${MIN_COVERAGE}%)${NC}"
else
echo -e "${GREEN}✓ Branches coverage (${BRANCHES}%) meets minimum${NC}"
fi
if (( $(echo "$FUNCTIONS < $MIN_COVERAGE" | bc -l) )); then
COVERAGE_OK=false
echo -e "${RED}✗ Functions coverage (${FUNCTIONS}%) below minimum (${MIN_COVERAGE}%)${NC}"
else
echo -e "${GREEN}✓ Functions coverage (${FUNCTIONS}%) meets minimum${NC}"
fi
if (( $(echo "$LINES < $MIN_COVERAGE" | bc -l) )); then
COVERAGE_OK=false
echo -e "${RED}✗ Lines coverage (${LINES}%) below minimum (${MIN_COVERAGE}%)${NC}"
else
echo -e "${GREEN}✓ Lines coverage (${LINES}%) meets minimum${NC}"
fi
echo ""
# Find files with low coverage
echo "Files with Coverage < ${MIN_COVERAGE}%:"
jq -r --arg min "$MIN_COVERAGE" '
. as $root |
to_entries[] |
select(.key != "total") |
select(.value.lines.pct < ($min | tonumber)) |
"\(.key): \(.value.lines.pct)%"
' "$COVERAGE_SUMMARY" | head -20
echo ""
if [ "$COVERAGE_OK" = true ]; then
echo -e "${GREEN}Status: PASSED - Test coverage is adequate${NC}"
echo ""
echo "✓ Safe to refactor - code is well tested"
exit 0
else
echo -e "${RED}Status: FAILED - Test coverage insufficient${NC}"
echo ""
echo "⚠ Recommendations:"
echo "1. Add tests before refactoring"
echo "2. Focus refactoring on well-tested code"
echo "3. Write tests for critical paths first"
echo ""
exit 1
fi
fi
fi
fi
# If we get here, couldn't parse coverage
echo -e "${YELLOW}Warning: Could not parse coverage report${NC}"
echo "Coverage file: $COVERAGE_SUMMARY"
echo ""
echo "Please verify test coverage manually before refactoring."
exit 0

771
commands/refactor/README.md Normal file
View File

@@ -0,0 +1,771 @@
# Code Refactoring Skill
Comprehensive code refactoring operations for improving code quality, maintainability, and architecture without changing external behavior.
## Overview
The refactor skill provides systematic, safety-first refactoring operations that follow industry best practices. It helps you identify code quality issues, eliminate technical debt, and modernize legacy code while maintaining test coverage and preserving external behavior.
**Key Principles:**
- **Preserve Behavior**: External behavior must remain unchanged
- **Safety First**: Verify test coverage before refactoring
- **Small Steps**: Incremental changes with frequent testing
- **Test-Driven**: Tests pass before, during, and after refactoring
- **One Thing at a Time**: Don't mix refactoring with feature development
- **Reversible**: Easy to revert if something goes wrong
## Available Operations
| Operation | Description | Use When |
|-----------|-------------|----------|
| **analyze** | Analyze code quality and identify opportunities | Starting refactoring session, need metrics |
| **extract** | Extract methods, classes, modules, components | Functions too long, repeated code |
| **patterns** | Introduce design patterns | Complex conditionals, tight coupling |
| **types** | Improve TypeScript type safety | Using 'any', weak types, no types |
| **duplicate** | Eliminate code duplication | Copy-paste code, DRY violations |
| **modernize** | Update legacy code patterns | Callbacks, var, jQuery, class components |
## Usage
### Basic Syntax
```bash
/10x-fullstack-engineer:refactor <operation> <parameters>
```
### Parameter Format
All operations use key:value parameter format:
```bash
/10x-fullstack-engineer:refactor analyze scope:"src/" metrics:"complexity,duplication" depth:"detailed"
/10x-fullstack-engineer:refactor extract scope:"UserService.ts" type:"method" target:"validateEmail"
/10x-fullstack-engineer:refactor patterns scope:"services/" pattern:"dependency-injection"
```
## Operations Guide
### 1. Analyze - Code Quality Analysis
Identify refactoring opportunities through comprehensive code analysis.
**Parameters:**
- `scope` (required): Path to analyze
- `metrics` (optional): Comma-separated metrics (default: all)
- `complexity` - Cyclomatic complexity
- `duplication` - Code duplication detection
- `coverage` - Test coverage analysis
- `dependencies` - Circular dependency detection
- `types` - TypeScript type coverage
- `smells` - Code smells detection
- `depth` (optional): `quick` | `standard` | `detailed` (default: standard)
**Example:**
```bash
/10x-fullstack-engineer:refactor analyze scope:"src/components" metrics:"complexity,duplication,coverage" depth:"detailed"
```
**What it measures:**
- **Complexity**: Functions with cyclomatic complexity > 10 (high risk)
- **Duplication**: Duplicate code blocks (exact and near matches)
- **Coverage**: Test coverage per file (target: >70%)
- **Dependencies**: Circular dependencies and tight coupling
- **Type Safety**: Usage of 'any' types in TypeScript
- **Code Smells**: Long methods, large classes, switch statements
**Output:** Comprehensive report with prioritized refactoring opportunities, metrics, and estimated effort.
---
### 2. Extract - Method/Class/Module Extraction
Extract code into smaller, focused units to reduce complexity.
**Parameters:**
- `scope` (required): File or module to refactor
- `type` (required): What to extract
- `method` - Extract method/function
- `class` - Extract class from large class
- `module` - Extract module from large file
- `component` - Extract React/Vue component
- `utility` - Extract utility function
- `interface` - Extract TypeScript interface/type
- `target` (required): What to extract (name or description)
- `reason` (optional): Motivation for extraction
**Examples:**
```bash
# Extract long method
/10x-fullstack-engineer:refactor extract scope:"UserService.ts" type:"method" target:"validateAndCreateUser" reason:"reduce complexity"
# Extract reusable component
/10x-fullstack-engineer:refactor extract scope:"UserProfile.tsx" type:"component" target:"ProfileHeader" reason:"reusability"
# Extract shared utility
/10x-fullstack-engineer:refactor extract scope:"formatters.js" type:"utility" target:"formatDate" reason:"used in multiple places"
```
**When to extract:**
- **Method**: Function >50 lines, complexity >10, duplicated logic
- **Class**: Class >300 lines, multiple responsibilities
- **Module**: File >500 lines, unrelated functions
- **Component**: Component >200 lines, reusable UI pattern
- **Utility**: Pure function used in multiple places
- **Interface**: Complex type used in multiple files
**Before/After Example:**
```typescript
// Before: 73 lines, complexity 15
async registerUser(userData: any) {
// 20 lines of validation
// 5 lines of existence check
// 3 lines of password hashing
// 10 lines of user creation
// 15 lines of email sending
// 10 lines of activity logging
// 10 lines of result mapping
}
// After: 12 lines, complexity 3
async registerUser(userData: RegisterUserInput): Promise<UserDTO> {
await this.validateRegistration(userData);
await this.checkEmailAvailability(userData.email);
const hashedPassword = await this.hashPassword(userData.password);
const user = await this.createUser({ ...userData, password: hashedPassword });
await this.sendRegistrationEmails(user);
await this.logRegistrationActivity(user);
return this.mapToDTO(user);
}
```
---
### 3. Patterns - Design Pattern Introduction
Introduce proven design patterns to solve recurring design problems.
**Parameters:**
- `scope` (required): Path to apply pattern
- `pattern` (required): Pattern to introduce
- `factory` - Create objects without specifying exact class
- `strategy` - Encapsulate interchangeable algorithms
- `observer` - Publish-subscribe event system
- `decorator` - Add behavior dynamically
- `adapter` - Make incompatible interfaces work together
- `repository` - Abstract data access layer
- `dependency-injection` - Invert control, improve testability
- `singleton` - Ensure single instance (use sparingly)
- `command` - Encapsulate requests as objects
- `facade` - Simplified interface to complex subsystem
- `reason` (optional): Why introducing this pattern
**Examples:**
```bash
# Eliminate complex switch statement
/10x-fullstack-engineer:refactor patterns scope:"PaymentProcessor.ts" pattern:"strategy" reason:"eliminate switch statement"
# Improve testability
/10x-fullstack-engineer:refactor patterns scope:"services/" pattern:"dependency-injection" reason:"improve testability"
# Decouple event handling
/10x-fullstack-engineer:refactor patterns scope:"UserService.ts" pattern:"observer" reason:"loose coupling"
```
**Pattern Selection Guide:**
| Problem | Pattern | Benefit |
|---------|---------|---------|
| Complex switch/conditionals | Strategy, State | Eliminate conditionals |
| Tight coupling | Dependency Injection, Observer | Loose coupling |
| Complex object creation | Factory, Builder | Centralize creation |
| Can't extend without modifying | Strategy, Decorator | Open/Closed Principle |
| Complex subsystem interface | Facade, Adapter | Simplify interface |
| Data access scattered | Repository | Abstract persistence |
**Before/After Example:**
```typescript
// Before: 180 lines, switch statement with 5 cases
async processPayment(order: Order, method: string) {
switch (method) {
case 'credit_card': /* 40 lines */ break;
case 'paypal': /* 40 lines */ break;
case 'bank_transfer': /* 40 lines */ break;
case 'crypto': /* 40 lines */ break;
}
}
// After: Strategy Pattern, ~30 lines
async processPayment(order: Order, method: string): Promise<PaymentResult> {
const strategy = this.strategies.get(method);
if (!strategy) throw new UnsupportedPaymentMethodError(method);
const result = await strategy.process(order);
await this.transactionRepo.record(order.id, result);
await this.notificationService.sendReceipt(order.customer, result);
return result;
}
```
---
### 4. Types - TypeScript Type Safety
Improve TypeScript type safety by eliminating 'any', adding types, and enabling strict mode.
**Parameters:**
- `scope` (required): Path to improve
- `strategy` (required): Type improvement strategy
- `add-types` - Add missing type annotations
- `strengthen-types` - Replace weak types with specific ones
- `migrate-to-ts` - Convert JavaScript to TypeScript
- `eliminate-any` - Remove 'any' types
- `add-generics` - Add generic type parameters
- `strict` (optional): Enable strict TypeScript mode (default: false)
**Examples:**
```bash
# Add missing types
/10x-fullstack-engineer:refactor types scope:"utils/helpers.js" strategy:"add-types"
# Eliminate all 'any' types
/10x-fullstack-engineer:refactor types scope:"api/" strategy:"eliminate-any" strict:"true"
# Migrate JavaScript to TypeScript
/10x-fullstack-engineer:refactor types scope:"src/legacy/" strategy:"migrate-to-ts"
# Add generics for reusability
/10x-fullstack-engineer:refactor types scope:"Repository.ts" strategy:"add-generics"
```
**Type Safety Improvements:**
| Strategy | Before | After | Benefit |
|----------|--------|-------|---------|
| add-types | `function process(data) { }` | `function process(data: Input): Output { }` | Compile-time checks |
| eliminate-any | `async get(): Promise<any>` | `async get<T>(): Promise<T>` | Type safety |
| migrate-to-ts | `.js` with no types | `.ts` with full types | Modern TypeScript |
| add-generics | Separate class per type | `Repository<T>` | DRY, reusable |
| strengthen-types | Weak 'any' types | Strong specific types | Catch errors early |
**Before/After Example:**
```typescript
// Before: Weak 'any' types
async get(endpoint: string): Promise<any> {
return fetch(endpoint).then(r => r.json());
}
// After: Strong generic types
async get<T>(endpoint: string): Promise<T> {
const response = await fetch(endpoint);
if (!response.ok) throw await this.handleError(response);
return response.json() as T;
}
// Usage with full type safety
const user = await client.get<User>('/users/1');
console.log(user.name); // Autocomplete works!
```
---
### 5. Duplicate - Code Duplication Elimination
Detect and eliminate code duplication through extraction, parameterization, or templating.
**Parameters:**
- `scope` (required): Path to analyze
- `threshold` (optional): Similarity percentage (default: 80)
- 100: Exact duplicates only
- 80-99: Near duplicates (recommended)
- 50-79: Similar patterns
- `strategy` (optional): Consolidation strategy (default: auto-detect)
- `extract-function` - Extract to shared function
- `extract-class` - Extract to shared class
- `parameterize` - Add parameters to reduce duplication
- `template` - Use template/component pattern
**Examples:**
```bash
# Find and eliminate duplicates
/10x-fullstack-engineer:refactor duplicate scope:"src/validators" threshold:"80" strategy:"extract-function"
# Find exact duplicates only
/10x-fullstack-engineer:refactor duplicate scope:"src/components" threshold:"100"
# Use parameterization
/10x-fullstack-engineer:refactor duplicate scope:"formatters.ts" strategy:"parameterize"
```
**Duplication Metrics:**
- **Target**: < 3% code duplication
- **Exact Duplicates**: 100% match (copy-paste code)
- **Near Duplicates**: 80-99% similar (minor variations)
- **Structural Duplicates**: 50-79% similar (same pattern)
**Before/After Example:**
```typescript
// Before: 5 copies of validation (210 lines duplicated)
// UserForm.tsx, ProfileForm.tsx, RegistrationForm.tsx, SettingsForm.tsx, AdminForm.tsx
function validateForm() {
const errors: Errors = {};
// 42 lines of validation logic copied in each file
return errors;
}
// After: Single implementation (168 lines saved)
// utils/validation.ts
export function validateUserForm(data: FormData): ValidationResult {
const errors: Record<string, string> = {};
const emailError = validateEmail(data.email);
if (emailError) errors.email = emailError;
const passwordError = validatePassword(data.password);
if (passwordError) errors.password = passwordError;
return { valid: Object.keys(errors).length === 0, errors };
}
// All forms import and use shared validation
import { validateUserForm } from '@/utils/validation';
```
---
### 6. Modernize - Legacy Code Modernization
Update legacy code patterns to modern JavaScript/TypeScript standards.
**Parameters:**
- `scope` (required): Path to modernize
- `targets` (required): Comma-separated modernization targets
- `callbacks-to-async` - Convert callbacks to async/await
- `var-to-const` - Replace var with const/let
- `prototypes-to-classes` - Convert prototypes to ES6 classes
- `commonjs-to-esm` - Convert CommonJS to ES modules
- `jquery-to-vanilla` - Replace jQuery with vanilla JS
- `classes-to-hooks` - Convert React class components to hooks
- `legacy-api` - Update deprecated API usage
- `compatibility` (optional): Target environment (e.g., "node14+", "es2020")
**Examples:**
```bash
# Modernize callback hell
/10x-fullstack-engineer:refactor modernize scope:"legacy-api/" targets:"callbacks-to-async" compatibility:"node14+"
# Update all legacy patterns
/10x-fullstack-engineer:refactor modernize scope:"src/old/" targets:"var-to-const,prototypes-to-classes,commonjs-to-esm"
# Remove jQuery dependency
/10x-fullstack-engineer:refactor modernize scope:"public/js/" targets:"jquery-to-vanilla"
# Convert to React hooks
/10x-fullstack-engineer:refactor modernize scope:"components/" targets:"classes-to-hooks"
```
**Modernization Impact:**
| Target | Improvement | Benefit |
|--------|-------------|---------|
| callbacks-to-async | Flat code vs callback hell | Readability, error handling |
| var-to-const | Block scope vs function scope | Prevent bugs, clarity |
| prototypes-to-classes | ES6 class syntax | Modern, better IDE support |
| commonjs-to-esm | import/export vs require() | Tree-shaking, standard |
| jquery-to-vanilla | Native APIs vs jQuery | -30KB bundle, performance |
| classes-to-hooks | Function components vs classes | Simpler, composable |
**Before/After Example:**
```javascript
// Before: Callback hell (25+ lines, nested 4 levels)
function getUser(userId, callback) {
db.query('SELECT * FROM users WHERE id = ?', [userId], function(err, user) {
if (err) return callback(err);
db.query('SELECT * FROM posts WHERE author_id = ?', [userId], function(err, posts) {
if (err) return callback(err);
db.query('SELECT * FROM comments WHERE user_id = ?', [userId], function(err, comments) {
if (err) return callback(err);
callback(null, { user, posts, comments });
});
});
});
}
// After: Async/await (8 lines, flat structure)
async function getUser(userId: number): Promise<UserWithContent> {
const [user, posts, comments] = await Promise.all([
query<User>('SELECT * FROM users WHERE id = ?', [userId]),
query<Post[]>('SELECT * FROM posts WHERE author_id = ?', [userId]),
query<Comment[]>('SELECT * FROM comments WHERE user_id = ?', [userId])
]);
return { user, posts, comments };
}
```
## Pre-Refactoring Safety Checklist
**CRITICAL**: Before ANY refactoring operation, verify:
### ✓ Test Coverage
- [ ] Existing test coverage is adequate (>70% for code being refactored)
- [ ] All tests currently passing
- [ ] Tests are meaningful (test behavior, not implementation)
### ✓ Version Control
- [ ] All changes committed to version control
- [ ] Working on a feature branch (not main/master)
- [ ] Clean working directory (no uncommitted changes)
### ✓ Backup
- [ ] Current state committed with clear message
- [ ] Can easily revert if needed
- [ ] Branch created specifically for this refactoring
### ✓ Scope Definition
- [ ] Clearly defined boundaries of what to refactor
- [ ] No mixing of refactoring with new features
- [ ] Reasonable size for one refactoring session
### ✓ Risk Assessment
- [ ] Understand dependencies and impact
- [ ] Identify potential breaking changes
- [ ] Have rollback plan ready
## Utility Scripts
The refactor skill includes three utility scripts for automated analysis:
### analyze-complexity.sh
Analyzes cyclomatic complexity using ESLint.
```bash
./.scripts/analyze-complexity.sh <scope> [max-complexity]
```
**Features:**
- Detects functions with complexity > threshold
- Identifies deep nesting (>3 levels)
- Finds long functions (>50 lines)
- Checks parameter counts (>4 parameters)
- Generates JSON report with violations
**Output:** `complexity-report.json`
### detect-duplication.sh
Detects code duplication using jsinspect.
```bash
./.scripts/detect-duplication.sh <scope> [threshold]
```
**Features:**
- Finds exact duplicates (100% match)
- Detects near duplicates (>80% similar)
- Identifies structural duplicates
- Calculates duplication statistics
- Provides remediation recommendations
**Output:** `duplication-report.json`
### verify-tests.sh
Verifies test coverage before refactoring.
```bash
./.scripts/verify-tests.sh <scope> [min-coverage]
```
**Features:**
- Runs tests with coverage
- Validates coverage meets minimum threshold
- Identifies files with low coverage
- Prevents unsafe refactoring
- Supports Jest, Mocha, NYC
**Output:** `coverage-report.json`
**Exit codes:**
- 0: Coverage adequate, safe to refactor
- 1: Insufficient coverage, add tests first
## Refactoring Techniques
### Code Smells and Solutions
| Code Smell | Detection | Solution | Operation |
|------------|-----------|----------|-----------|
| **Long Method** | >50 lines | Extract smaller methods | extract |
| **Long Parameter List** | >4 parameters | Introduce parameter object | extract |
| **Duplicate Code** | >3% duplication | Extract to shared function | duplicate |
| **Large Class** | >300 lines | Split into focused classes | extract |
| **Switch Statements** | Complex conditionals | Use polymorphism/strategy | patterns |
| **Feature Envy** | Method uses another class heavily | Move method to that class | extract |
| **Data Clumps** | Same data grouped together | Introduce class/interface | extract |
| **Primitive Obsession** | Primitives instead of objects | Introduce value objects | patterns |
### Refactoring Workflows
#### Workflow 1: High Complexity Function
```bash
# 1. Analyze complexity
/10x-fullstack-engineer:refactor analyze scope:"UserService.ts" metrics:"complexity"
# 2. Identify function with complexity >10
# Result: validateAndCreateUser() has complexity 18
# 3. Extract methods
/10x-fullstack-engineer:refactor extract scope:"UserService.ts" type:"method" target:"validateAndCreateUser"
# 4. Verify improvement
/10x-fullstack-engineer:refactor analyze scope:"UserService.ts" metrics:"complexity"
# Result: Complexity reduced from 18 to 3
```
#### Workflow 2: Code Duplication
```bash
# 1. Detect duplication
/10x-fullstack-engineer:refactor duplicate scope:"src/components" threshold:"80"
# 2. Review duplicate blocks
# Result: Validation logic duplicated in 5 files
# 3. Extract to shared utility
/10x-fullstack-engineer:refactor duplicate scope:"src/components" strategy:"extract-function"
# 4. Verify elimination
/10x-fullstack-engineer:refactor duplicate scope:"src/components" threshold:"80"
# Result: Duplication reduced from 6.6% to 1.1%
```
#### Workflow 3: Legacy Code Modernization
```bash
# 1. Identify legacy patterns
/10x-fullstack-engineer:refactor analyze scope:"src/legacy/" metrics:"all"
# 2. Modernize callbacks to async/await
/10x-fullstack-engineer:refactor modernize scope:"src/legacy/" targets:"callbacks-to-async"
# 3. Update var to const/let
/10x-fullstack-engineer:refactor modernize scope:"src/legacy/" targets:"var-to-const"
# 4. Convert to ES modules
/10x-fullstack-engineer:refactor modernize scope:"src/legacy/" targets:"commonjs-to-esm"
# 5. Verify all tests pass
npm test
```
## Best Practices
### Do's
**Start Small**: Begin with low-risk, high-value refactorings
**Test Continuously**: Run tests after each change
**Commit Frequently**: Small commits with clear messages
**Pair Review**: Have someone review refactored code
**Measure Impact**: Track metrics before and after
**Document Why**: Explain reasoning in commits and comments
**Avoid Scope Creep**: Stay focused on defined scope
**Time Box**: Set time limits for refactoring sessions
### Don'ts
**Mix with Features**: Don't add features while refactoring
**Skip Tests**: Never refactor code with <70% coverage
**Big Bang**: Avoid massive refactorings
**Change Behavior**: External behavior must stay the same
**Uncommitted Changes**: Always commit before refactoring
**Ignore Warnings**: Address all compiler/linter warnings
**Over-Engineer**: Apply patterns only when truly needed
**Rush**: Take time to refactor properly
## Metrics and Goals
### Code Quality Targets
| Metric | Target | Warning | Critical |
|--------|--------|---------|----------|
| Cyclomatic Complexity | <6 | 6-10 | >10 |
| Function Length | <50 lines | 50-100 | >100 |
| Class Length | <300 lines | 300-500 | >500 |
| Parameter Count | <4 | 4-6 | >6 |
| Code Duplication | <3% | 3-8% | >8% |
| Test Coverage | >80% | 70-80% | <70% |
| Type Coverage (TS) | >95% | 90-95% | <90% |
### Refactoring Impact
Track these metrics before and after refactoring:
- **Complexity Reduction**: Cyclomatic complexity decrease
- **Lines of Code**: Reduction through extraction and DRY
- **Test Coverage**: Improvement in coverage percentage
- **Type Safety**: Reduction in 'any' usage
- **Duplication**: Percentage of duplicate code eliminated
- **Bundle Size**: Reduction (e.g., removing jQuery)
## Integration with 10x-fullstack-engineer Agent
All refactoring operations leverage the **10x-fullstack-engineer** agent for:
- Expert code quality analysis
- Best practice application
- Pattern recognition and recommendation
- Consistency with project standards
- Risk assessment and mitigation
- Test-driven refactoring approach
The agent applies **SOLID principles**, **DRY**, **YAGNI**, and follows the **Boy Scout Rule** (leave code better than you found it).
## Common Issues and Solutions
### Issue: "Insufficient test coverage"
**Solution:**
```bash
# 1. Check current coverage
/10x-fullstack-engineer:refactor analyze scope:"UserService.ts" metrics:"coverage"
# 2. Add tests before refactoring
# Write tests for the code you're about to refactor
# 3. Verify coverage improved
npm test -- --coverage
# 4. Retry refactoring
/10x-fullstack-engineer:refactor extract scope:"UserService.ts" type:"method" target:"validateUser"
```
### Issue: "Uncommitted changes detected"
**Solution:**
```bash
# 1. Check git status
git status
# 2. Commit or stash changes
git add .
git commit -m "chore: prepare for refactoring"
# 3. Create refactoring branch
git checkout -b refactor/improve-user-service
# 4. Retry refactoring
/10x-fullstack-engineer:refactor extract scope:"UserService.ts" type:"method" target:"validateUser"
```
### Issue: "Too many duplicates found"
**Solution:**
```bash
# 1. Increase threshold to focus on exact duplicates
/10x-fullstack-engineer:refactor duplicate scope:"src/" threshold:"95"
# 2. Tackle highest impact duplicates first
# Extract most duplicated code blocks
# 3. Gradually lower threshold
/10x-fullstack-engineer:refactor duplicate scope:"src/" threshold:"85"
# 4. Continue until <3% duplication
/10x-fullstack-engineer:refactor duplicate scope:"src/" threshold:"80"
```
## Examples
### Complete Refactoring Session
```bash
# Session: Refactor UserService for better maintainability
# Step 1: Analyze current state
/10x-fullstack-engineer:refactor analyze scope:"src/services/UserService.ts" depth:"detailed"
# Results:
# - Complexity: 18 (CRITICAL)
# - Duplication: 6.6% (HIGH)
# - Coverage: 65% (INADEQUATE)
# Step 2: Add tests to reach >70% coverage
# (Write tests for critical paths)
# Step 3: Verify coverage improved
npm test -- --coverage
# Coverage: 78% ✓
# Step 4: Extract complex method
/10x-fullstack-engineer:refactor extract scope:"src/services/UserService.ts" type:"method" target:"validateAndCreateUser"
# Complexity: 18 → 3 (83% improvement)
# Step 5: Introduce dependency injection pattern
/10x-fullstack-engineer:refactor patterns scope:"src/services/UserService.ts" pattern:"dependency-injection"
# Testability: Greatly improved
# Step 6: Eliminate duplicate validation
/10x-fullstack-engineer:refactor duplicate scope:"src/services/" threshold:"80" strategy:"extract-function"
# Duplication: 6.6% → 1.1% (87.5% improvement)
# Step 7: Strengthen types
/10x-fullstack-engineer:refactor types scope:"src/services/UserService.ts" strategy:"eliminate-any"
# Type safety: 100% (0 'any' types remaining)
# Step 8: Final analysis
/10x-fullstack-engineer:refactor analyze scope:"src/services/UserService.ts" depth:"detailed"
# Results:
# - Complexity: 3 (EXCELLENT)
# - Duplication: 1.1% (EXCELLENT)
# - Coverage: 85% (GOOD)
# - Type Safety: 100% (EXCELLENT)
# Step 9: Run all tests
npm test
# All tests passing ✓
# Step 10: Commit refactoring
git add .
git commit -m "refactor(UserService): improve maintainability and testability
- Reduced complexity from 18 to 3
- Eliminated 87.5% of code duplication
- Improved test coverage from 65% to 85%
- Removed all 'any' types
- Introduced dependency injection pattern"
```
## Related Skills
- `/test` - Test generation and coverage improvement
- `/review` - Code review and quality checks
- `/debug` - Debugging and issue diagnosis
- `/optimize` - Performance optimization
## Further Reading
- **Refactoring (Martin Fowler)**: Definitive guide to refactoring
- **Clean Code (Robert C. Martin)**: Code quality principles
- **Design Patterns (Gang of Four)**: Pattern catalog
- **Working Effectively with Legacy Code (Michael Feathers)**: Legacy modernization
- **Refactoring UI (Adam Wathan)**: Component extraction patterns
---
**Remember**: Refactoring is not about making code perfect—it's about making code better, more maintainable, and easier to change in the future. Refactor continuously, in small steps, with confidence provided by comprehensive test coverage.

View File

@@ -0,0 +1,659 @@
# Code Quality Analysis Operation
Analyze code quality, identify code smells, calculate metrics, and prioritize refactoring opportunities.
## Parameters
**Received from $ARGUMENTS**: All arguments after "analyze"
**Expected format**:
```
scope:"<path-or-description>" [metrics:"<metric1,metric2>"] [depth:"quick|standard|detailed"]
```
**Parameter definitions**:
- `scope` (REQUIRED): Path to analyze or description (e.g., "user-service/", "authentication module", "src/components/UserProfile.tsx")
- `metrics` (OPTIONAL): Comma-separated metrics to analyze (default: all)
- `complexity` - Cyclomatic complexity
- `duplication` - Code duplication detection
- `coverage` - Test coverage analysis
- `dependencies` - Dependency analysis and circular dependencies
- `types` - Type coverage (TypeScript projects)
- `smells` - Code smells detection
- `depth` (OPTIONAL): Analysis depth (default: standard)
- `quick` - Fast scan, high-level metrics only
- `standard` - Balanced analysis with key metrics
- `detailed` - Comprehensive deep analysis with recommendations
## Workflow
### 1. Pre-Analysis Verification
Before analyzing, verify:
```bash
# Check if scope exists
test -e <scope> || echo "Error: Scope path does not exist"
# Check if project has package.json
test -f package.json || echo "Warning: No package.json found"
# Verify analysis tools availability
command -v npx >/dev/null 2>&1 || echo "Warning: npm/npx not available"
```
### 2. Complexity Analysis
**Measure cyclomatic complexity** using ESLint:
```bash
# Run complexity analysis
npx eslint <scope> \
--ext .js,.jsx,.ts,.tsx \
--rule 'complexity: [error, { max: 10 }]' \
--rule 'max-depth: [error, 3]' \
--rule 'max-lines-per-function: [error, { max: 50 }]' \
--rule 'max-params: [error, 4]' \
--format json > complexity-report.json
# Or use script
./.scripts/analyze-complexity.sh <scope>
```
**Identify**:
- Functions with complexity > 10 (high risk)
- Functions with complexity 6-10 (moderate risk)
- Deep nesting (>3 levels)
- Long functions (>50 lines)
- Long parameter lists (>4 parameters)
**Report format**:
```markdown
### Complexity Analysis
**Critical Issues** (Complexity > 10):
1. `UserService.validateAndCreateUser()` - Complexity: 18 (45 lines)
- Location: src/services/UserService.ts:127
- Impact: High - Used in 8 places
- Recommendation: Extract validation logic into separate functions
2. `OrderProcessor.processPayment()` - Complexity: 15 (38 lines)
- Location: src/services/OrderProcessor.ts:89
- Impact: Medium - Payment critical path
- Recommendation: Use strategy pattern for payment methods
**Moderate Issues** (Complexity 6-10):
- 12 functions identified
- Average complexity: 7.3
- Recommendation: Monitor, refactor opportunistically
```
### 3. Duplication Detection
**Detect duplicate code** using jsinspect:
```bash
# Find duplicated code blocks
npx jsinspect <scope> \
--threshold 30 \
--min-instances 2 \
--ignore "node_modules|dist|build" \
--reporter json > duplication-report.json
# Or use script
./.scripts/detect-duplication.sh <scope>
```
**Identify**:
- Exact duplicates (100% match)
- Near duplicates (>80% similar)
- Copy-paste patterns
- Repeated logic across files
**Report format**:
```markdown
### Code Duplication
**Exact Duplicates** (100% match):
1. Validation logic (42 lines) - 5 instances
- src/components/UserForm.tsx:45-87
- src/components/ProfileForm.tsx:32-74
- src/components/RegistrationForm.tsx:56-98
- src/components/SettingsForm.tsx:23-65
- src/components/AdminForm.tsx:89-131
- **Recommendation**: Extract to shared validator utility
- **Estimated savings**: 168 lines (4 duplicates × 42 lines)
**Near Duplicates** (>80% similar):
2. API error handling (18 lines) - 8 instances
- Average similarity: 87%
- **Recommendation**: Create centralized error handler
- **Estimated savings**: 126 lines
**Total Duplication**:
- Duplicate lines: 542 / 8,234 (6.6%)
- Target: < 3%
- **Priority**: HIGH - Significant duplication found
```
### 4. Test Coverage Analysis
**Calculate test coverage**:
```bash
# Run tests with coverage
npm test -- --coverage --watchAll=false
# Generate coverage report
npx nyc report --reporter=json > coverage-report.json
# Or use script
./.scripts/verify-tests.sh <scope>
```
**Identify**:
- Files with < 70% coverage (inadequate)
- Files with 70-80% coverage (acceptable)
- Files with > 80% coverage (good)
- Untested code paths
- Missing edge case tests
**Report format**:
```markdown
### Test Coverage
**Overall Coverage**:
- Statements: 78.5% (Target: 80%)
- Branches: 72.3% (Target: 75%)
- Functions: 81.2% (Target: 80%)
- Lines: 77.8% (Target: 80%)
**Critical Gaps** (< 70% coverage):
1. `src/services/PaymentService.ts` - 45% coverage
- Missing: Error handling paths
- Missing: Edge cases (negative amounts, invalid cards)
- **Risk**: HIGH - Financial logic
2. `src/utils/validation.ts` - 62% coverage
- Missing: Boundary conditions
- Missing: Invalid input handling
- **Risk**: MEDIUM - Used in 15 components
**Recommendation**: Add tests before refactoring these areas.
```
### 5. Dependency Analysis
**Analyze module dependencies**:
```bash
# Check for circular dependencies
npx madge --circular --extensions ts,tsx,js,jsx <scope>
# Generate dependency graph
npx madge --image deps.png <scope>
# Find orphaned files
npx madge --orphans <scope>
```
**Identify**:
- Circular dependencies (breaks modularity)
- Highly coupled modules
- God objects (too many dependencies)
- Orphaned files (unused)
- Deep dependency chains
**Report format**:
```markdown
### Dependency Analysis
**Circular Dependencies** (CRITICAL):
1. UserService ↔ AuthService ↔ SessionService
- **Impact**: Cannot test in isolation
- **Recommendation**: Introduce interface/abstraction layer
2. OrderModel ↔ PaymentModel ↔ CustomerModel
- **Impact**: Tight coupling, difficult to change
- **Recommendation**: Use repository pattern
**High Coupling**:
- `UserService.ts` - 23 dependencies (Target: < 10)
- `AppConfig.ts` - 18 dependencies (Target: < 10)
- **Recommendation**: Split into smaller, focused modules
**Orphaned Files**: 5 files unused
- src/utils/old-validator.ts (can be deleted)
- src/helpers/deprecated.ts (can be deleted)
```
### 6. Type Coverage Analysis (TypeScript)
**Analyze TypeScript type safety**:
```bash
# Type check with strict mode
npx tsc --noEmit --strict
# Count 'any' usage
grep -r "any" <scope> --include="*.ts" --include="*.tsx" | wc -l
# Check for implicit any
npx tsc --noEmit --noImplicitAny
```
**Identify**:
- Usage of `any` type
- Implicit any declarations
- Missing return type annotations
- Weak type definitions
- Type assertion overuse
**Report format**:
```markdown
### Type Safety Analysis (TypeScript)
**Type Coverage**:
- Files with types: 145 / 167 (87%)
- Any usage: 42 instances (Target: 0)
- Implicit any: 18 instances
- **Rating**: MODERATE - Room for improvement
**Critical Issues**:
1. `src/api/client.ts` - 12 'any' types
- Functions without return types
- Untyped API responses
- **Recommendation**: Add proper interfaces for API contracts
2. `src/utils/helpers.ts` - 8 'any' types
- Generic utility functions
- **Recommendation**: Use generics instead of 'any'
**Opportunity**: Eliminate 'any' types for 23% improvement
```
### 7. Code Smells Detection
**Identify common code smells**:
**Long Method** (>50 lines):
- Difficult to understand
- Hard to test
- Often doing too much
- **Fix**: Extract smaller methods
**Long Parameter List** (>4 parameters):
- Difficult to use
- Hard to remember order
- Often indicates missing abstraction
- **Fix**: Introduce parameter object
**Duplicate Code**:
- Maintenance nightmare
- Bug multiplication
- **Fix**: Extract to shared function/component
**Large Class** (>300 lines):
- Too many responsibilities
- Hard to understand
- Difficult to test
- **Fix**: Split into smaller classes
**Switch Statements** (complex conditionals):
- Hard to extend
- Violates Open/Closed Principle
- **Fix**: Use polymorphism or strategy pattern
**Report format**:
```markdown
### Code Smells Detected
**Long Methods**: 23 functions > 50 lines
- Worst: `OrderService.processOrder()` (247 lines)
- **Impact**: Extremely difficult to understand and maintain
- **Priority**: CRITICAL
**Long Parameter Lists**: 18 functions > 4 parameters
- Worst: `createUser(name, email, age, address, phone, role, settings)` (7 params)
- **Fix**: Use `CreateUserParams` object
**Large Classes**: 8 classes > 300 lines
- Worst: `UserService.ts` (842 lines)
- **Responsibilities**: Validation, CRUD, Auth, Notifications, Logging
- **Fix**: Split into focused services
**Switch Statements**: 12 complex conditionals
- `src/services/PaymentProcessor.ts` - Switch on payment method (5 cases, 180 lines)
- **Fix**: Use strategy pattern for payment methods
```
### 8. Generate Prioritized Report
**Priority calculation** based on:
- **Severity**: Critical > High > Medium > Low
- **Impact**: How many files/components affected
- **Risk**: Test coverage, complexity, usage frequency
- **Effort**: Estimated time to fix (hours)
- **Value**: Improvement in maintainability
**Report format**:
```markdown
## Code Quality Analysis Report
### Executive Summary
**Scope Analyzed**: <scope>
**Analysis Date**: <date>
**Total Files**: <count>
**Total Lines**: <count>
**Overall Health Score**: 6.5 / 10 (Needs Improvement)
**Top Priorities**:
1. Eliminate critical code duplication (HIGH)
2. Refactor high-complexity functions (HIGH)
3. Improve test coverage for critical paths (HIGH)
4. Remove circular dependencies (MEDIUM)
5. Strengthen TypeScript type safety (MEDIUM)
---
### Metrics Summary
| Metric | Current | Target | Status |
|--------|---------|--------|--------|
| Cyclomatic Complexity (avg) | 8.3 | < 6 | ⚠️ Above target |
| Code Duplication | 6.6% | < 3% | ⚠️ Above target |
| Test Coverage | 78.5% | > 80% | ⚠️ Below target |
| Type Coverage | 87% | > 95% | ⚠️ Below target |
| Circular Dependencies | 3 | 0 | ❌ Critical |
---
### Priority 1: Critical Issues (Fix Immediately)
#### 1.1 Circular Dependencies
**Severity**: CRITICAL
**Impact**: Cannot test modules in isolation, tight coupling
**Files Affected**: 8
**Dependencies**:
- UserService ↔ AuthService ↔ SessionService
- OrderModel ↔ PaymentModel ↔ CustomerModel
- ComponentA ↔ ComponentB ↔ ComponentC
**Recommendation**: Introduce dependency injection and interface abstractions
**Estimated Effort**: 8 hours
**Value**: HIGH - Enables independent testing and deployment
#### 1.2 Extremely High Complexity Functions
**Severity**: CRITICAL
**Impact**: Very difficult to understand, test, maintain
**Functions**: 4
**Functions**:
1. `UserService.validateAndCreateUser()` - Complexity: 18
2. `OrderProcessor.processPayment()` - Complexity: 15
3. `ReportGenerator.generateQuarterly()` - Complexity: 14
4. `DataTransformer.transform()` - Complexity: 13
**Recommendation**: Extract smaller functions, use early returns
**Estimated Effort**: 6 hours
**Value**: HIGH - Dramatic readability improvement
---
### Priority 2: High Issues (Fix Soon)
#### 2.1 Significant Code Duplication
**Severity**: HIGH
**Impact**: Maintenance burden, bug multiplication
**Duplicate Code**:
- Validation logic: 5 exact copies (210 lines duplicated)
- Error handling: 8 similar copies (144 lines duplicated)
- Data formatting: 6 copies (96 lines duplicated)
**Recommendation**: Extract to shared utilities
**Estimated Effort**: 4 hours
**Value**: HIGH - 450 lines reduction, single source of truth
#### 2.2 Inadequate Test Coverage
**Severity**: HIGH
**Impact**: High risk of regressions during refactoring
**Critical Gaps**:
- `PaymentService.ts` - 45% coverage (Financial logic!)
- `AuthService.ts` - 58% coverage (Security logic!)
- `validation.ts` - 62% coverage (Used everywhere!)
**Recommendation**: Add comprehensive tests before ANY refactoring
**Estimated Effort**: 8 hours
**Value**: CRITICAL - Enables safe refactoring
---
### Priority 3: Medium Issues (Plan to Fix)
#### 3.1 TypeScript Type Safety
**Severity**: MEDIUM
**Impact**: Runtime errors, poor IDE support
**Issues**:
- 42 usages of 'any' type
- 18 implicit any declarations
- Missing return type annotations
**Recommendation**: Eliminate 'any', add proper types
**Estimated Effort**: 6 hours
**Value**: MEDIUM - Catch errors at compile time
#### 3.2 Long Methods and Large Classes
**Severity**: MEDIUM
**Impact**: Difficult to understand and maintain
**Issues**:
- 23 long methods (>50 lines)
- 8 large classes (>300 lines)
- Single Responsibility Principle violations
**Recommendation**: Extract methods and split classes
**Estimated Effort**: 12 hours
**Value**: MEDIUM - Improved maintainability
---
### Priority 4: Low Issues (Opportunistic)
- Rename unclear variables (quick wins)
- Add missing JSDoc comments
- Consolidate similar utility functions
- Remove unused imports and variables
---
### Recommended Refactoring Sequence
**Week 1**:
1. Add missing tests for critical paths (8 hrs)
2. Fix circular dependencies (8 hrs)
**Week 2**:
3. Eliminate critical code duplication (4 hrs)
4. Refactor highest complexity functions (6 hrs)
**Week 3**:
5. Strengthen TypeScript types (6 hrs)
6. Extract long methods (6 hrs)
**Week 4**:
7. Split large classes (6 hrs)
8. Address remaining medium priority issues
**Total Estimated Effort**: ~54 hours
---
### Code Examples
#### Example 1: High Complexity Function
**Before** (Complexity: 18):
```typescript
async validateAndCreateUser(userData: any) {
if (!userData.email) {
throw new Error("Email required");
}
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(userData.email)) {
throw new Error("Invalid email");
}
if (!userData.password || userData.password.length < 8) {
throw new Error("Password must be at least 8 characters");
}
const hasUpper = /[A-Z]/.test(userData.password);
const hasLower = /[a-z]/.test(userData.password);
const hasNumber = /[0-9]/.test(userData.password);
if (!hasUpper || !hasLower || !hasNumber) {
throw new Error("Password must contain uppercase, lowercase, and number");
}
const existing = await this.db.users.findOne({ email: userData.email });
if (existing) {
throw new Error("Email already registered");
}
const hashedPassword = await bcrypt.hash(userData.password, 10);
const user = await this.db.users.create({
email: userData.email,
password: hashedPassword,
name: userData.name,
createdAt: new Date()
});
await this.emailService.sendWelcomeEmail(user.email);
return user;
}
```
**After** (Complexity: 3):
```typescript
async validateAndCreateUser(userData: CreateUserInput): Promise<User> {
this.validateUserInput(userData);
await this.checkEmailAvailability(userData.email);
const hashedPassword = await this.hashPassword(userData.password);
const user = await this.createUser({ ...userData, password: hashedPassword });
await this.sendWelcomeEmail(user);
return user;
}
private validateUserInput(userData: CreateUserInput): void {
validateEmail(userData.email);
validatePassword(userData.password);
}
private async checkEmailAvailability(email: string): Promise<void> {
const existing = await this.db.users.findOne({ email });
if (existing) {
throw new UserAlreadyExistsError(email);
}
}
private async hashPassword(password: string): Promise<string> {
return bcrypt.hash(password, 10);
}
private async createUser(data: CreateUserData): Promise<User> {
return this.db.users.create({
...data,
createdAt: new Date()
});
}
private async sendWelcomeEmail(user: User): Promise<void> {
await this.emailService.sendWelcomeEmail(user.email);
}
```
**Improvements**:
- Complexity: 18 → 3 (83% reduction)
- Lines per function: 37 → 5 (86% reduction)
- Testability: Each function can be tested independently
- Readability: Clear intent, self-documenting code
- Type safety: Proper interfaces instead of 'any'
---
### Next Steps
Based on this analysis, consider:
1. **Immediate Actions**:
- Add tests for PaymentService, AuthService, validation.ts
- Fix circular dependencies
- Review and approve refactoring priorities
2. **Use Refactoring Operations**:
- `/refactor extract` - For long methods
- `/refactor duplicate` - For code duplication
- `/refactor patterns` - For circular dependencies (DI pattern)
- `/refactor types` - For TypeScript improvements
3. **Continuous Monitoring**:
- Set up automated complexity checks in CI/CD
- Track duplication metrics over time
- Monitor test coverage trends
- Review code quality in pull requests
---
**Analysis Complete**: Refactoring priorities identified and prioritized by impact and effort.
```
## Output Format
Provide a comprehensive analysis report with:
- Executive summary with health score
- Metrics table (current vs target)
- Prioritized issues (Critical → High → Medium → Low)
- Code examples showing before/after improvements
- Estimated effort and value for each issue
- Recommended refactoring sequence
- Next steps and monitoring recommendations
## Error Handling
**Scope not found**:
```
Error: Specified scope does not exist: <scope>
Please provide a valid path or description:
- Relative path: "src/components/"
- Absolute path: "/full/path/to/code"
- Module description: "user authentication module"
```
**No metrics requested**:
```
Using default metrics: complexity, duplication, coverage, dependencies
To specify metrics: metrics:"complexity,duplication"
```
**Analysis tools not available**:
```
Warning: Some analysis tools not available:
- eslint: Install with 'npm install -D eslint'
- jsinspect: Install with 'npm install -g jsinspect'
Proceeding with available tools...
```

View File

@@ -0,0 +1,823 @@
# Code Duplication Elimination Operation
Detect and eliminate code duplication through extraction, parameterization, or templating.
## Parameters
**Received from $ARGUMENTS**: All arguments after "duplicate"
**Expected format**:
```
scope:"<path>" [threshold:"<percentage>"] [strategy:"<strategy-name>"]
```
**Parameter definitions**:
- `scope` (REQUIRED): Path to analyze (e.g., "src/", "src/components/")
- `threshold` (OPTIONAL): Similarity threshold percentage (default: 80)
- 100: Exact duplicates only
- 80-99: Near duplicates (recommended)
- 50-79: Similar patterns
- `strategy` (OPTIONAL): Consolidation strategy (default: auto-detect)
- `extract-function` - Extract to shared function
- `extract-class` - Extract to shared class
- `parameterize` - Add parameters to reduce duplication
- `template` - Use template/component pattern
## Workflow
### 1. Detect Duplication
Use jsinspect or similar tools:
```bash
# Find duplicate code blocks
npx jsinspect <scope> \
--threshold <threshold> \
--min-instances 2 \
--ignore "node_modules|dist|build|test" \
--reporter json
# Or use script
./.scripts/detect-duplication.sh <scope> <threshold>
```
### 2. Analyze Duplication Patterns
Categorize duplicates:
- **Exact duplicates** (100% match): Copy-paste code
- **Near duplicates** (80-99% match): Similar with minor differences
- **Structural duplicates** (50-79% match): Same pattern, different data
### 3. Choose Consolidation Strategy
Based on duplication type:
## Strategy Examples
### Strategy 1: Extract Function
**When to use**:
- Exact or near duplicate code blocks
- Pure logic with clear inputs/outputs
- Used in 2+ places
- No complex state dependencies
**Before** (Duplicated validation):
```typescript
// UserForm.tsx
function validateForm() {
const errors: Errors = {};
if (!formData.email) {
errors.email = "Email is required";
} else {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(formData.email)) {
errors.email = "Invalid email format";
}
}
if (!formData.password) {
errors.password = "Password is required";
} else if (formData.password.length < 8) {
errors.password = "Password must be at least 8 characters";
} else {
const hasUpper = /[A-Z]/.test(formData.password);
const hasLower = /[a-z]/.test(formData.password);
const hasNumber = /[0-9]/.test(formData.password);
if (!hasUpper || !hasLower || !hasNumber) {
errors.password = "Password must contain uppercase, lowercase, and number";
}
}
return errors;
}
// ProfileForm.tsx - Same validation copied
function validateForm() {
const errors: Errors = {};
if (!formData.email) {
errors.email = "Email is required";
} else {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(formData.email)) {
errors.email = "Invalid email format";
}
}
if (!formData.password) {
errors.password = "Password is required";
} else if (formData.password.length < 8) {
errors.password = "Password must be at least 8 characters";
} else {
const hasUpper = /[A-Z]/.test(formData.password);
const hasLower = /[a-z]/.test(formData.password);
const hasNumber = /[0-9]/.test(formData.password);
if (!hasUpper || !hasLower || !hasNumber) {
errors.password = "Password must contain uppercase, lowercase, and number";
}
}
return errors;
}
// RegistrationForm.tsx - Same validation copied again
// SettingsForm.tsx - Same validation copied again
// AdminForm.tsx - Same validation copied again
```
**After** (Extracted to shared utilities):
```typescript
// utils/validation.ts
export interface ValidationResult {
valid: boolean;
errors: Record<string, string>;
}
export function validateEmail(email: string): string | null {
if (!email) {
return "Email is required";
}
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) {
return "Invalid email format";
}
return null;
}
export function validatePassword(password: string): string | null {
if (!password) {
return "Password is required";
}
if (password.length < 8) {
return "Password must be at least 8 characters";
}
const hasUpper = /[A-Z]/.test(password);
const hasLower = /[a-z]/.test(password);
const hasNumber = /[0-9]/.test(password);
if (!hasUpper || !hasLower || !hasNumber) {
return "Password must contain uppercase, lowercase, and number";
}
return null;
}
export function validateUserForm(data: {
email: string;
password: string;
}): ValidationResult {
const errors: Record<string, string> = {};
const emailError = validateEmail(data.email);
if (emailError) errors.email = emailError;
const passwordError = validatePassword(data.password);
if (passwordError) errors.password = passwordError;
return {
valid: Object.keys(errors).length === 0,
errors
};
}
// All forms now use shared validation
// UserForm.tsx
import { validateUserForm } from '@/utils/validation';
function validateForm() {
return validateUserForm(formData);
}
// ProfileForm.tsx
import { validateUserForm } from '@/utils/validation';
function validateForm() {
return validateUserForm(formData);
}
// Same for RegistrationForm, SettingsForm, AdminForm
```
**Improvements**:
- DRY: 5 duplicates → 1 implementation
- Lines saved: ~200 lines (40 lines × 5 copies)
- Single source of truth: Fix bugs once
- Testability: Test validation independently
- Consistency: All forms use same validation
---
### Strategy 2: Extract Class
**When to use**:
- Duplicated logic with state
- Related methods copied together
- Object-oriented patterns
- Multiple functions working on same data
**Before** (Duplicated error handling across services):
```typescript
// UserService.ts
class UserService {
async createUser(data: any) {
try {
const user = await this.db.users.create(data);
return { success: true, data: user };
} catch (error) {
if (error.code === '23505') {
return {
success: false,
error: { code: 'DUPLICATE_EMAIL', message: 'Email already exists' }
};
}
if (error.code === '23503') {
return {
success: false,
error: { code: 'INVALID_REFERENCE', message: 'Invalid reference' }
};
}
console.error('User creation error:', error);
return {
success: false,
error: { code: 'INTERNAL_ERROR', message: 'Internal server error' }
};
}
}
}
// PostService.ts - Same error handling copied
class PostService {
async createPost(data: any) {
try {
const post = await this.db.posts.create(data);
return { success: true, data: post };
} catch (error) {
if (error.code === '23505') {
return {
success: false,
error: { code: 'DUPLICATE_TITLE', message: 'Title already exists' }
};
}
if (error.code === '23503') {
return {
success: false,
error: { code: 'INVALID_REFERENCE', message: 'Invalid reference' }
};
}
console.error('Post creation error:', error);
return {
success: false,
error: { code: 'INTERNAL_ERROR', message: 'Internal server error' }
};
}
}
}
// CommentService.ts - Same pattern copied
// OrderService.ts - Same pattern copied
```
**After** (Extracted error handler class):
```typescript
// errors/DatabaseErrorHandler.ts
export interface ErrorResponse {
code: string;
message: string;
details?: any;
}
export interface Result<T> {
success: boolean;
data?: T;
error?: ErrorResponse;
}
export class DatabaseErrorHandler {
private errorMappings: Map<string, (error: any) => ErrorResponse> = new Map([
['23505', this.handleDuplicateKey],
['23503', this.handleForeignKeyViolation],
['23502', this.handleNotNullViolation],
['23514', this.handleCheckViolation]
]);
handleError(error: any, context: string = 'Database'): ErrorResponse {
const handler = this.errorMappings.get(error.code);
if (handler) {
return handler.call(this, error);
}
console.error(`${context} error:`, error);
return {
code: 'INTERNAL_ERROR',
message: 'Internal server error'
};
}
private handleDuplicateKey(error: any): ErrorResponse {
return {
code: 'DUPLICATE_KEY',
message: 'Resource with this identifier already exists',
details: error.detail
};
}
private handleForeignKeyViolation(error: any): ErrorResponse {
return {
code: 'INVALID_REFERENCE',
message: 'Referenced resource does not exist',
details: error.detail
};
}
private handleNotNullViolation(error: any): ErrorResponse {
return {
code: 'MISSING_REQUIRED_FIELD',
message: 'Required field is missing',
details: error.column
};
}
private handleCheckViolation(error: any): ErrorResponse {
return {
code: 'CONSTRAINT_VIOLATION',
message: 'Data violates constraint',
details: error.constraint
};
}
async wrapOperation<T>(
operation: () => Promise<T>,
context?: string
): Promise<Result<T>> {
try {
const data = await operation();
return { success: true, data };
} catch (error) {
return {
success: false,
error: this.handleError(error, context)
};
}
}
}
// Services now use shared error handler
// UserService.ts
class UserService {
constructor(
private db: Database,
private errorHandler: DatabaseErrorHandler
) {}
async createUser(data: CreateUserInput): Promise<Result<User>> {
return this.errorHandler.wrapOperation(
() => this.db.users.create(data),
'User creation'
);
}
}
// PostService.ts
class PostService {
constructor(
private db: Database,
private errorHandler: DatabaseErrorHandler
) {}
async createPost(data: CreatePostInput): Promise<Result<Post>> {
return this.errorHandler.wrapOperation(
() => this.db.posts.create(data),
'Post creation'
);
}
}
// All services now use shared error handling
```
**Improvements**:
- Centralized error handling
- Consistent error responses
- Easier to extend (add new error types)
- Better logging and monitoring
- DRY: One error handler for all services
---
### Strategy 3: Parameterize
**When to use**:
- Functions differ only in values/configuration
- Similar structure, different data
- Can be unified with parameters
- Limited number of variations
**Before** (Similar functions with hard-coded values):
```typescript
// formatters.ts
function formatUserName(user: User): string {
return `${user.firstName} ${user.lastName}`;
}
function formatAdminName(admin: Admin): string {
return `${admin.firstName} ${admin.lastName} (Admin)`;
}
function formatModeratorName(moderator: Moderator): string {
return `${moderator.firstName} ${moderator.lastName} (Moderator)`;
}
function formatGuestName(guest: Guest): string {
return `Guest: ${guest.firstName} ${guest.lastName}`;
}
// Similar for emails
function formatUserEmail(user: User): string {
return user.email.toLowerCase();
}
function formatAdminEmail(admin: Admin): string {
return `admin-${admin.email.toLowerCase()}`;
}
function formatModeratorEmail(moderator: Moderator): string {
return `mod-${moderator.email.toLowerCase()}`;
}
```
**After** (Parameterized):
```typescript
// formatters.ts
interface Person {
firstName: string;
lastName: string;
email: string;
}
type NameFormat = {
prefix?: string;
suffix?: string;
template?: (person: Person) => string;
};
function formatName(person: Person, format: NameFormat = {}): string {
if (format.template) {
return format.template(person);
}
const base = `${person.firstName} ${person.lastName}`;
const prefix = format.prefix ? `${format.prefix}: ` : '';
const suffix = format.suffix ? ` (${format.suffix})` : '';
return `${prefix}${base}${suffix}`;
}
type EmailFormat = {
prefix?: string;
domain?: string;
transform?: (email: string) => string;
};
function formatEmail(person: Person, format: EmailFormat = {}): string {
let email = person.email.toLowerCase();
if (format.transform) {
email = format.transform(email);
}
if (format.prefix) {
const [local, domain] = email.split('@');
email = `${format.prefix}-${local}@${domain}`;
}
if (format.domain) {
const [local] = email.split('@');
email = `${local}@${format.domain}`;
}
return email;
}
// Usage - Much more flexible
const userName = formatName(user);
const adminName = formatName(admin, { suffix: 'Admin' });
const modName = formatName(moderator, { suffix: 'Moderator' });
const guestName = formatName(guest, { prefix: 'Guest' });
const userEmail = formatEmail(user);
const adminEmail = formatEmail(admin, { prefix: 'admin' });
const modEmail = formatEmail(moderator, { prefix: 'mod' });
// Easy to add new formats without new functions
const vipName = formatName(vip, { suffix: 'VIP', prefix: 'Special' });
const customEmail = formatEmail(user, {
transform: (email) => email.toUpperCase()
});
```
**Improvements**:
- 7 functions → 2 parameterized functions
- More flexible: Infinite combinations possible
- Easier to maintain: One function to update
- Easier to test: Test parameters instead of functions
- Extensible: Add new formats without new code
---
### Strategy 4: Template/Component Pattern
**When to use**:
- Repeated UI patterns
- Similar component structures
- Variations in content, not structure
- React/Vue component duplication
**Before** (Duplicated card components):
```typescript
// UserCard.tsx
function UserCard({ user }: { user: User }) {
return (
<div className="card">
<div className="card-header">
<img src={user.avatar} alt={user.name} />
<h3>{user.name}</h3>
</div>
<div className="card-body">
<p>{user.email}</p>
<p>{user.role}</p>
</div>
<div className="card-footer">
<button onClick={() => viewUser(user.id)}>View</button>
<button onClick={() => editUser(user.id)}>Edit</button>
</div>
</div>
);
}
// PostCard.tsx - Same structure copied
function PostCard({ post }: { post: Post }) {
return (
<div className="card">
<div className="card-header">
<img src={post.thumbnail} alt={post.title} />
<h3>{post.title}</h3>
</div>
<div className="card-body">
<p>{post.excerpt}</p>
<p>By {post.author}</p>
</div>
<div className="card-footer">
<button onClick={() => viewPost(post.id)}>View</button>
<button onClick={() => editPost(post.id)}>Edit</button>
</div>
</div>
);
}
// ProductCard.tsx - Same structure copied
// CommentCard.tsx - Same structure copied
```
**After** (Generic Card template):
```typescript
// components/Card.tsx
interface CardProps {
header: {
image: string;
title: string;
imageAlt?: string;
};
body: React.ReactNode;
footer?: {
actions: Array<{
label: string;
onClick: () => void;
variant?: 'primary' | 'secondary';
}>;
};
className?: string;
}
export function Card({ header, body, footer, className = '' }: CardProps) {
return (
<div className={`card ${className}`}>
<div className="card-header">
<img
src={header.image}
alt={header.imageAlt || header.title}
className="card-image"
/>
<h3 className="card-title">{header.title}</h3>
</div>
<div className="card-body">{body}</div>
{footer && (
<div className="card-footer">
{footer.actions.map((action, index) => (
<button
key={index}
onClick={action.onClick}
className={`btn btn-${action.variant || 'primary'}`}
>
{action.label}
</button>
))}
</div>
)}
</div>
);
}
// Usage - Much cleaner
// UserCard.tsx
function UserCard({ user }: { user: User }) {
return (
<Card
header={{
image: user.avatar,
title: user.name,
imageAlt: `${user.name}'s avatar`
}}
body={
<>
<p>{user.email}</p>
<p className="user-role">{user.role}</p>
</>
}
footer={{
actions: [
{ label: 'View', onClick: () => viewUser(user.id) },
{ label: 'Edit', onClick: () => editUser(user.id), variant: 'secondary' }
]
}}
/>
);
}
// PostCard.tsx
function PostCard({ post }: { post: Post }) {
return (
<Card
header={{
image: post.thumbnail,
title: post.title
}}
body={
<>
<p>{post.excerpt}</p>
<p className="post-author">By {post.author}</p>
</>
}
footer={{
actions: [
{ label: 'Read More', onClick: () => viewPost(post.id) },
{ label: 'Edit', onClick: () => editPost(post.id), variant: 'secondary' }
]
}}
/>
);
}
```
**Improvements**:
- Reusable Card component
- Consistent UI across cards
- Easy to change card structure globally
- Less code duplication
- Compose with different content
---
## Measurement
Calculate duplication savings:
```bash
# Before
Total lines: 10,000
Duplicate lines: 800 (8%)
# After
Total lines: 9,200
Duplicate lines: 100 (1.1%)
# Savings
Lines removed: 800
Duplication reduced: 8% → 1.1% (87.5% improvement)
```
## Output Format
```markdown
# Code Duplication Elimination Report
## Analysis
**Scope**: <path>
**Threshold**: <percentage>%
**Duplicates Found**:
- Exact duplicates: <count> instances
- Near duplicates: <count> instances
- Total duplicate lines: <count> / <total> (<percentage>%)
## Duplication Examples
### Duplicate 1: <description>
**Instances**: <count> copies
**Locations**:
1. <file1>:<line-range>
2. <file2>:<line-range>
3. <file3>:<line-range>
**Strategy**: <extract-function | extract-class | parameterize | template>
**Before** (<lines> lines duplicated):
```typescript
<duplicated-code>
```
**After** (Single implementation):
```typescript
<consolidated-code>
```
**Savings**: <lines> lines removed
## Total Impact
**Before**:
- Total lines: <count>
- Duplicate lines: <count> (<percentage>%)
**After**:
- Total lines: <count>
- Duplicate lines: <count> (<percentage>%)
**Improvement**:
- Lines removed: <count>
- Duplication reduced: <before>% → <after>% (<percentage>% improvement)
- Maintainability: Significantly improved
## Files Changed
**Created**:
- <new-shared-file-1>
- <new-shared-file-2>
**Modified**:
- <file-1>: Replaced with shared implementation
- <file-2>: Replaced with shared implementation
## Testing
**Tests Updated**:
- <test-file-1>: Updated to test shared code
- <test-file-2>: Removed duplicate tests
**Coverage**:
- Before: <percentage>%
- After: <percentage>%
## Next Steps
**Remaining Duplication**:
1. <duplicate-pattern-1>: <count> instances
2. <duplicate-pattern-2>: <count> instances
**Recommendations**:
- Continue eliminating duplicates
- Set up automated duplication detection in CI/CD
- Code review for new duplicates
---
**Duplication Eliminated**: Code is now DRY and maintainable.
```
## Error Handling
**No duplicates found**:
```
Success: No significant code duplication found (threshold: <percentage>%)
**Duplication**: <percentage>% (Target: < 3%)
The codebase is already DRY. Great work!
```
**Threshold too low**:
```
Warning: Threshold <percentage>% is very low. Found <count> potential duplicates.
Many may be false positives (similar structure but different purpose).
Recommendation: Use threshold 80-90% for meaningful duplicates.
```

1229
commands/refactor/extract.md Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,962 @@
# Legacy Code Modernization Operation
Update legacy code patterns to modern JavaScript/TypeScript standards and best practices.
## Parameters
**Received from $ARGUMENTS**: All arguments after "modernize"
**Expected format**:
```
scope:"<path>" targets:"<target1,target2>" [compatibility:"<version>"]
```
**Parameter definitions**:
- `scope` (REQUIRED): Path to modernize (e.g., "src/legacy/", "utils/old-helpers.js")
- `targets` (REQUIRED): Comma-separated modernization targets
- `callbacks-to-async` - Convert callbacks to async/await
- `var-to-const` - Replace var with const/let
- `prototypes-to-classes` - Convert prototypes to ES6 classes
- `commonjs-to-esm` - Convert CommonJS to ES modules
- `jquery-to-vanilla` - Replace jQuery with vanilla JS
- `classes-to-hooks` - Convert React class components to hooks
- `legacy-api` - Update deprecated API usage
- `compatibility` (OPTIONAL): Target environment (e.g., "node14+", "es2020", "modern-browsers")
## Workflow
### 1. Analyze Legacy Patterns
Identify legacy code to modernize:
```bash
# Find var usage
grep -r "var " <scope> --include="*.js" --include="*.ts"
# Find callback patterns
grep -r "function.*callback" <scope>
# Find prototype usage
grep -r ".prototype" <scope>
# Find require() usage
grep -r "require\(" <scope>
# Find jQuery usage
grep -r "\$\(" <scope>
```
### 2. Target-Specific Modernization
## Modernization Examples
### Target 1: Callbacks to Async/Await
**When to modernize**:
- Callback hell (deeply nested callbacks)
- Error handling is scattered
- Readability suffers
- Modern runtime supports async/await
**Before** (Callback hell):
```javascript
// database.js
function getUser(userId, callback) {
db.query('SELECT * FROM users WHERE id = ?', [userId], function(err, user) {
if (err) {
return callback(err);
}
db.query('SELECT * FROM posts WHERE author_id = ?', [userId], function(err, posts) {
if (err) {
return callback(err);
}
db.query('SELECT * FROM comments WHERE user_id = ?', [userId], function(err, comments) {
if (err) {
return callback(err);
}
callback(null, {
user: user,
posts: posts,
comments: comments
});
});
});
});
}
// Usage
getUser(123, function(err, data) {
if (err) {
console.error('Error:', err);
return;
}
console.log('User:', data.user);
console.log('Posts:', data.posts);
console.log('Comments:', data.comments);
});
```
**After** (Async/await - Clean and readable):
```typescript
// database.ts
import { query } from './db';
interface User {
id: number;
name: string;
email: string;
}
interface Post {
id: number;
title: string;
content: string;
authorId: number;
}
interface Comment {
id: number;
content: string;
userId: number;
}
interface UserWithContent {
user: User;
posts: Post[];
comments: Comment[];
}
async function getUser(userId: number): Promise<UserWithContent> {
// Parallel execution for better performance
const [user, posts, comments] = await Promise.all([
query<User>('SELECT * FROM users WHERE id = ?', [userId]),
query<Post[]>('SELECT * FROM posts WHERE author_id = ?', [userId]),
query<Comment[]>('SELECT * FROM comments WHERE user_id = ?', [userId])
]);
return { user, posts, comments };
}
// Usage - Much cleaner
try {
const data = await getUser(123);
console.log('User:', data.user);
console.log('Posts:', data.posts);
console.log('Comments:', data.comments);
} catch (error) {
console.error('Error:', error);
}
```
**More callback conversions**:
```javascript
// Before: fs callbacks
const fs = require('fs');
fs.readFile('config.json', 'utf8', function(err, data) {
if (err) {
console.error(err);
return;
}
const config = JSON.parse(data);
fs.writeFile('output.json', JSON.stringify(config), function(err) {
if (err) {
console.error(err);
return;
}
console.log('Done');
});
});
// After: fs promises
import { readFile, writeFile } from 'fs/promises';
try {
const data = await readFile('config.json', 'utf8');
const config = JSON.parse(data);
await writeFile('output.json', JSON.stringify(config));
console.log('Done');
} catch (error) {
console.error(error);
}
```
**Improvements**:
- No callback hell: Flat, linear code
- Better error handling: Single try/catch
- Parallel execution: Promise.all() for performance
- Type safety: Full TypeScript support
- Readability: Much easier to understand
---
### Target 2: var to const/let
**When to modernize**:
- Using old var declarations
- Want block scoping
- Prevent accidental reassignment
- Modern ES6+ environment
**Before** (var - function scoped, hoisted):
```javascript
function processOrders() {
var total = 0;
var count = 0;
for (var i = 0; i < orders.length; i++) {
var order = orders[i];
var price = order.price;
var quantity = order.quantity;
total += price * quantity;
count++;
}
// i is still accessible here (function scoped!)
console.log(i); // orders.length
return { total: total, count: count };
}
// Hoisting issues
function example() {
console.log(x); // undefined (not error)
var x = 10;
}
// Loop issues
for (var i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i); // Always prints 3!
}, 100);
}
```
**After** (const/let - block scoped, not hoisted):
```typescript
function processOrders(): { total: number; count: number } {
let total = 0;
let count = 0;
for (let i = 0; i < orders.length; i++) {
const order = orders[i];
const price = order.price;
const quantity = order.quantity;
total += price * quantity;
count++;
}
// i is NOT accessible here (block scoped)
// console.log(i); // Error: i is not defined
return { total, count };
}
// No hoisting issues
function example() {
console.log(x); // Error: Cannot access 'x' before initialization
const x = 10;
}
// Loop fixed
for (let i = 0; i < 3; i++) {
setTimeout(() => {
console.log(i); // Prints 0, 1, 2 correctly
}, 100);
}
```
**Guidelines**:
- Use `const` by default (immutable binding)
- Use `let` when reassignment needed
- Never use `var` in modern code
- Block scope prevents many bugs
---
### Target 3: Prototypes to ES6 Classes
**When to modernize**:
- Using prototype-based inheritance
- Want cleaner OOP syntax
- Better IDE support needed
- Modern JavaScript environment
**Before** (Prototype pattern):
```javascript
// Animal.js
function Animal(name, age) {
this.name = name;
this.age = age;
}
Animal.prototype.speak = function() {
console.log(this.name + ' makes a sound');
};
Animal.prototype.getInfo = function() {
return this.name + ' is ' + this.age + ' years old';
};
// Dog.js
function Dog(name, age, breed) {
Animal.call(this, name, age);
this.breed = breed;
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.speak = function() {
console.log(this.name + ' barks');
};
Dog.prototype.fetch = function() {
console.log(this.name + ' fetches the ball');
};
// Usage
var dog = new Dog('Rex', 3, 'Labrador');
dog.speak(); // Rex barks
console.log(dog.getInfo()); // Rex is 3 years old
```
**After** (ES6 Classes):
```typescript
// Animal.ts
export class Animal {
constructor(
protected name: string,
protected age: number
) {}
speak(): void {
console.log(`${this.name} makes a sound`);
}
getInfo(): string {
return `${this.name} is ${this.age} years old`;
}
}
// Dog.ts
export class Dog extends Animal {
constructor(
name: string,
age: number,
private breed: string
) {
super(name, age);
}
speak(): void {
console.log(`${this.name} barks`);
}
fetch(): void {
console.log(`${this.name} fetches the ball`);
}
getBreed(): string {
return this.breed;
}
}
// Usage
const dog = new Dog('Rex', 3, 'Labrador');
dog.speak(); // Rex barks
console.log(dog.getInfo()); // Rex is 3 years old
console.log(dog.getBreed()); // Labrador
```
**Improvements**:
- Cleaner syntax: More readable
- Better inheritance: extends keyword
- Access modifiers: public, private, protected
- Type safety: Full TypeScript support
- IDE support: Better autocomplete
---
### Target 4: CommonJS to ES Modules
**When to modernize**:
- Using require() and module.exports
- Want tree-shaking benefits
- Modern bundler support
- Better static analysis
**Before** (CommonJS):
```javascript
// utils.js
const crypto = require('crypto');
const fs = require('fs');
function generateId() {
return crypto.randomUUID();
}
function readConfig() {
return JSON.parse(fs.readFileSync('config.json', 'utf8'));
}
module.exports = {
generateId,
readConfig
};
// user-service.js
const { generateId } = require('./utils');
const db = require('./database');
class UserService {
async createUser(data) {
const id = generateId();
return db.users.create({ ...data, id });
}
}
module.exports = UserService;
// index.js
const express = require('express');
const UserService = require('./user-service');
const app = express();
const userService = new UserService();
app.post('/users', async (req, res) => {
const user = await userService.createUser(req.body);
res.json(user);
});
module.exports = app;
```
**After** (ES Modules):
```typescript
// utils.ts
import { randomUUID } from 'crypto';
import { readFileSync } from 'fs';
export function generateId(): string {
return randomUUID();
}
export function readConfig(): Config {
return JSON.parse(readFileSync('config.json', 'utf8'));
}
// user-service.ts
import { generateId } from './utils.js';
import { db } from './database.js';
export class UserService {
async createUser(data: CreateUserInput): Promise<User> {
const id = generateId();
return db.users.create({ ...data, id });
}
}
// index.ts
import express from 'express';
import { UserService } from './user-service.js';
const app = express();
const userService = new UserService();
app.post('/users', async (req, res) => {
const user = await userService.createUser(req.body);
res.json(user);
});
export default app;
```
**Improvements**:
- Tree-shaking: Remove unused exports
- Static imports: Better bundler optimization
- Named exports: More explicit imports
- Top-level await: Possible in ES modules
- Standard: Modern JavaScript standard
---
### Target 5: jQuery to Vanilla JavaScript
**When to modernize**:
- Remove jQuery dependency
- Reduce bundle size
- Modern browsers support native APIs
- Better performance
**Before** (jQuery):
```javascript
// app.js - Heavy jQuery usage
$(document).ready(function() {
// DOM selection
var $button = $('#submit-button');
var $form = $('.user-form');
var $inputs = $form.find('input');
// Event handling
$button.on('click', function(e) {
e.preventDefault();
// Get form data
var formData = {};
$inputs.each(function() {
var $input = $(this);
formData[$input.attr('name')] = $input.val();
});
// AJAX request
$.ajax({
url: '/api/users',
method: 'POST',
data: JSON.stringify(formData),
contentType: 'application/json',
success: function(response) {
// DOM manipulation
var $message = $('<div>')
.addClass('success-message')
.text('User created successfully!');
$form.after($message);
$message.fadeIn().delay(3000).fadeOut();
// Clear form
$inputs.val('');
},
error: function(xhr) {
$('.error-message').text(xhr.responseText).show();
}
});
});
// Show/hide password
$('.toggle-password').on('click', function() {
var $input = $(this).siblings('input');
var type = $input.attr('type');
$input.attr('type', type === 'password' ? 'text' : 'password');
$(this).toggleClass('active');
});
});
```
**After** (Vanilla JavaScript):
```typescript
// app.ts - Modern vanilla JavaScript
document.addEventListener('DOMContentLoaded', () => {
// DOM selection - Native APIs
const button = document.querySelector<HTMLButtonElement>('#submit-button');
const form = document.querySelector<HTMLFormElement>('.user-form');
const inputs = form?.querySelectorAll<HTMLInputElement>('input');
if (!button || !form || !inputs) return;
// Event handling - addEventListener
button.addEventListener('click', async (e) => {
e.preventDefault();
// Get form data - FormData API
const formData = new FormData(form);
const data = Object.fromEntries(formData.entries());
try {
// Fetch API instead of $.ajax
const response = await fetch('/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
if (!response.ok) {
throw new Error(await response.text());
}
const user = await response.json();
// DOM manipulation - Native APIs
const message = document.createElement('div');
message.className = 'success-message';
message.textContent = 'User created successfully!';
form.insertAdjacentElement('afterend', message);
// CSS animations instead of jQuery animations
message.style.opacity = '0';
message.style.display = 'block';
requestAnimationFrame(() => {
message.style.transition = 'opacity 0.3s';
message.style.opacity = '1';
setTimeout(() => {
message.style.opacity = '0';
setTimeout(() => message.remove(), 300);
}, 3000);
});
// Clear form
form.reset();
} catch (error) {
const errorMessage = document.querySelector('.error-message');
if (errorMessage) {
errorMessage.textContent = error.message;
errorMessage.style.display = 'block';
}
}
});
// Show/hide password - Native APIs
const toggleButtons = document.querySelectorAll<HTMLButtonElement>('.toggle-password');
toggleButtons.forEach(toggle => {
toggle.addEventListener('click', () => {
const input = toggle.previousElementSibling as HTMLInputElement;
if (!input) return;
const type = input.type === 'password' ? 'text' : 'password';
input.type = type;
toggle.classList.toggle('active');
});
});
});
```
**Bundle size impact**:
- Before: ~30KB (jQuery minified + gzipped)
- After: ~0KB (native APIs)
- **Savings**: 30KB, faster load time
**Improvements**:
- No jQuery dependency
- Modern native APIs
- Better performance
- TypeScript support
- Smaller bundle size
---
### Target 6: React Class Components to Hooks
**When to modernize**:
- Using class components
- Want simpler code
- Better functional composition
- Modern React patterns
**Before** (Class component):
```typescript
// UserProfile.tsx
import React, { Component } from 'react';
interface Props {
userId: string;
}
interface State {
user: User | null;
loading: boolean;
error: Error | null;
}
class UserProfile extends Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
user: null,
loading: true,
error: null
};
this.handleRefresh = this.handleRefresh.bind(this);
}
componentDidMount() {
this.loadUser();
}
componentDidUpdate(prevProps: Props) {
if (prevProps.userId !== this.props.userId) {
this.loadUser();
}
}
async loadUser() {
this.setState({ loading: true, error: null });
try {
const response = await fetch(`/api/users/${this.props.userId}`);
const user = await response.json();
this.setState({ user, loading: false });
} catch (error) {
this.setState({ error, loading: false });
}
}
handleRefresh() {
this.loadUser();
}
render() {
const { user, loading, error } = this.state;
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
if (!user) return <div>User not found</div>;
return (
<div className="user-profile">
<h1>{user.name}</h1>
<p>{user.email}</p>
<button onClick={this.handleRefresh}>Refresh</button>
</div>
);
}
}
export default UserProfile;
```
**After** (Function component with hooks):
```typescript
// UserProfile.tsx
import { useState, useEffect } from 'react';
interface Props {
userId: string;
}
export function UserProfile({ userId }: Props) {
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);
// Extract to custom hook for reusability
const loadUser = async () => {
setLoading(true);
setError(null);
try {
const response = await fetch(`/api/users/${userId}`);
const userData = await response.json();
setUser(userData);
} catch (err) {
setError(err as Error);
} finally {
setLoading(false);
}
};
// Load user on mount and when userId changes
useEffect(() => {
loadUser();
}, [userId]);
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
if (!user) return <div>User not found</div>;
return (
<div className="user-profile">
<h1>{user.name}</h1>
<p>{user.email}</p>
<button onClick={loadUser}>Refresh</button>
</div>
);
}
```
**Even better with custom hook**:
```typescript
// hooks/useUser.ts
import { useState, useEffect } from 'react';
export function useUser(userId: string) {
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);
const loadUser = async () => {
setLoading(true);
setError(null);
try {
const response = await fetch(`/api/users/${userId}`);
const userData = await response.json();
setUser(userData);
} catch (err) {
setError(err as Error);
} finally {
setLoading(false);
}
};
useEffect(() => {
loadUser();
}, [userId]);
return { user, loading, error, refresh: loadUser };
}
// UserProfile.tsx - Super clean now!
export function UserProfile({ userId }: { userId: string }) {
const { user, loading, error, refresh } = useUser(userId);
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
if (!user) return <div>User not found</div>;
return (
<div className="user-profile">
<h1>{user.name}</h1>
<p>{user.email}</p>
<button onClick={refresh}>Refresh</button>
</div>
);
}
```
**Improvements**:
- Less boilerplate: No constructor, bind, etc.
- Simpler: Function instead of class
- Reusability: Custom hooks
- Better composition: Hooks compose well
- Modern: Current React best practice
---
## Output Format
```markdown
# Legacy Code Modernization Report
## Targets Modernized: <target1, target2, ...>
**Scope**: <path>
**Compatibility**: <version>
## Before Modernization
**Legacy Patterns Found**:
- var declarations: <count>
- Callback functions: <count>
- Prototype usage: <count>
- CommonJS modules: <count>
- jQuery usage: <count>
- Class components: <count>
**Issues**:
- Callback hell in <count> files
- Poor error handling
- Large bundle size (jQuery dependency)
- Outdated syntax
## Modernization Performed
### Target 1: <target-name>
**Files Modified**: <count>
**Before**:
```javascript
<legacy-code>
```
**After**:
```typescript
<modern-code>
```
**Improvements**:
- <improvement 1>
- <improvement 2>
### Target 2: <target-name>
[Same structure...]
## After Modernization
**Modern Patterns**:
- const/let: <count> conversions
- Async/await: <count> conversions
- ES6 classes: <count> conversions
- ES modules: <count> conversions
- Vanilla JS: <count> jQuery removals
- Function components: <count> conversions
**Metrics**:
- Bundle size: <before>KB → <after>KB (<percentage>% reduction)
- Code quality: Significantly improved
- Maintainability: Much easier
- Performance: <improvement>
## Testing
**Tests Updated**: <count>
**All tests passing**: YES
**New tests added**: <count>
## Breaking Changes
<list-breaking-changes-or-none>
## Migration Guide
**For Consumers**:
```typescript
// Old API
<old-usage>
// New API
<new-usage>
```
## Next Steps
**Further Modernization**:
1. <next-opportunity>
2. <another-opportunity>
---
**Modernization Complete**: Codebase updated to modern standards.
```
## Error Handling
**Incompatible environment**:
```
Error: Target environment does not support <feature>
Target: <compatibility>
Required: <minimum-version>
Options:
1. Use Babel/TypeScript to transpile
2. Update target environment
3. Choose different modernization target
```
**Too many changes**:
```
Warning: Modernizing <count> files is a large change.
Recommendation: Gradual modernization
1. Start with critical paths
2. Modernize incrementally
3. Test thoroughly between changes
4. Review with team
```

View File

@@ -0,0 +1,845 @@
# Design Pattern Introduction Operation
Introduce proven design patterns to solve recurring design problems and improve code structure.
## Parameters
**Received from $ARGUMENTS**: All arguments after "patterns"
**Expected format**:
```
scope:"<path>" pattern:"<pattern-name>" [reason:"<motivation>"]
```
**Parameter definitions**:
- `scope` (REQUIRED): Path to apply pattern (e.g., "src/services/", "src/components/UserForm.tsx")
- `pattern` (REQUIRED): Pattern to introduce
- `factory` - Create objects without specifying exact class
- `strategy` - Encapsulate interchangeable algorithms
- `observer` - Publish-subscribe event system
- `decorator` - Add behavior dynamically
- `adapter` - Make incompatible interfaces work together
- `repository` - Abstract data access layer
- `dependency-injection` - Invert control, improve testability
- `singleton` - Ensure single instance (use sparingly!)
- `command` - Encapsulate requests as objects
- `facade` - Simplified interface to complex subsystem
- `reason` (OPTIONAL): Why introducing this pattern (e.g., "eliminate switch statement", "improve testability")
## Workflow
### 1. Pattern Selection Validation
Verify pattern is appropriate for the problem:
**Anti-patterns to avoid**:
- Using pattern for pattern's sake (over-engineering)
- Singleton when not needed (global state)
- Factory when simple constructor suffices
- Strategy for only 2 simple options
**Good reasons to introduce pattern**:
- Eliminate complex conditional logic (Strategy, State)
- Improve testability (Dependency Injection, Repository)
- Enable extensibility without modification (Strategy, Decorator, Observer)
- Simplify complex interface (Facade, Adapter)
- Separate concerns (Repository, Factory)
### 2. Analyze Current Code Structure
Understand what needs to change:
```bash
# Find relevant files
find <scope> -type f -name "*.ts" -o -name "*.tsx"
# Analyze complexity
npx eslint <scope> --rule 'complexity: [error, { max: 10 }]'
# Check dependencies
npx madge <scope>
```
### 3. Pattern-Specific Implementation
## Pattern Examples
### Pattern 1: Factory Pattern
**Use when**:
- Object creation is complex
- Need to choose between multiple implementations
- Want to hide creation logic
- Need centralized object creation
**Before** (Direct instantiation everywhere):
```typescript
// Scattered throughout codebase
const emailNotif = new EmailNotification(config);
await emailNotif.send(user, message);
const smsNotif = new SMSNotification(twilioConfig);
await smsNotif.send(user, message);
const pushNotif = new PushNotification(fcmConfig);
await pushNotif.send(user, message);
// Different interfaces, hard to extend
```
**After** (Factory Pattern):
```typescript
// notifications/NotificationFactory.ts
interface Notification {
send(user: User, message: string): Promise<void>;
}
export class NotificationFactory {
constructor(private config: NotificationConfig) {}
create(type: NotificationType): Notification {
switch (type) {
case 'email':
return new EmailNotification(this.config.email);
case 'sms':
return new SMSNotification(this.config.sms);
case 'push':
return new PushNotification(this.config.push);
default:
throw new Error(`Unknown notification type: ${type}`);
}
}
}
// Usage
const factory = new NotificationFactory(config);
const notification = factory.create(user.preferences.notificationType);
await notification.send(user, message);
```
**Improvements**:
- Centralized creation logic
- Consistent interface
- Easy to add new notification types
- Configuration hidden from consumers
---
### Pattern 2: Strategy Pattern
**Use when**:
- Multiple algorithms for same task
- Need to switch algorithms at runtime
- Want to eliminate complex conditionals
- Algorithms have different implementations but same interface
**Before** (Complex switch statement):
```typescript
// PaymentProcessor.ts - 180 lines, complexity: 15
class PaymentProcessor {
async processPayment(order: Order, method: string) {
switch (method) {
case 'credit_card':
// 40 lines of credit card processing
const ccGateway = new CreditCardGateway(this.config.stripe);
const ccToken = await ccGateway.tokenize(order.paymentDetails);
const ccCharge = await ccGateway.charge(ccToken, order.amount);
await this.recordTransaction(order.id, ccCharge);
await this.sendReceipt(order.customer, ccCharge);
return ccCharge;
case 'paypal':
// 40 lines of PayPal processing
const ppGateway = new PayPalGateway(this.config.paypal);
const ppAuth = await ppGateway.authenticate();
const ppPayment = await ppGateway.createPayment(order);
await this.recordTransaction(order.id, ppPayment);
await this.sendReceipt(order.customer, ppPayment);
return ppPayment;
case 'bank_transfer':
// 40 lines of bank transfer processing
const btGateway = new BankTransferGateway(this.config.bank);
const btReference = await btGateway.generateReference(order);
await this.sendInstructions(order.customer, btReference);
await this.recordTransaction(order.id, btReference);
return btReference;
case 'crypto':
// 40 lines of crypto processing
const cryptoGateway = new CryptoGateway(this.config.crypto);
const wallet = await cryptoGateway.generateAddress();
await this.sendInstructions(order.customer, wallet);
await this.recordTransaction(order.id, wallet);
return wallet;
default:
throw new Error(`Unsupported payment method: ${method}`);
}
}
}
```
**After** (Strategy Pattern):
```typescript
// payment/PaymentStrategy.ts
export interface PaymentStrategy {
process(order: Order): Promise<PaymentResult>;
}
// payment/strategies/CreditCardStrategy.ts
export class CreditCardStrategy implements PaymentStrategy {
constructor(private gateway: CreditCardGateway) {}
async process(order: Order): Promise<PaymentResult> {
const token = await this.gateway.tokenize(order.paymentDetails);
const charge = await this.gateway.charge(token, order.amount);
return {
success: true,
transactionId: charge.id,
method: 'credit_card'
};
}
}
// payment/strategies/PayPalStrategy.ts
export class PayPalStrategy implements PaymentStrategy {
constructor(private gateway: PayPalGateway) {}
async process(order: Order): Promise<PaymentResult> {
await this.gateway.authenticate();
const payment = await this.gateway.createPayment(order);
return {
success: true,
transactionId: payment.id,
method: 'paypal'
};
}
}
// payment/strategies/BankTransferStrategy.ts
export class BankTransferStrategy implements PaymentStrategy {
constructor(private gateway: BankTransferGateway) {}
async process(order: Order): Promise<PaymentResult> {
const reference = await this.gateway.generateReference(order);
return {
success: true,
transactionId: reference,
method: 'bank_transfer',
requiresManualConfirmation: true
};
}
}
// payment/PaymentProcessor.ts - Now clean and extensible
export class PaymentProcessor {
private strategies: Map<string, PaymentStrategy>;
constructor(
strategies: Map<string, PaymentStrategy>,
private transactionRepo: TransactionRepository,
private notificationService: NotificationService
) {
this.strategies = strategies;
}
async processPayment(order: Order, method: string): Promise<PaymentResult> {
const strategy = this.strategies.get(method);
if (!strategy) {
throw new UnsupportedPaymentMethodError(method);
}
const result = await strategy.process(order);
await this.transactionRepo.record(order.id, result);
await this.notificationService.sendReceipt(order.customer, result);
return result;
}
}
// Setup (dependency injection)
const processor = new PaymentProcessor(
new Map([
['credit_card', new CreditCardStrategy(ccGateway)],
['paypal', new PayPalStrategy(ppGateway)],
['bank_transfer', new BankTransferStrategy(btGateway)],
['crypto', new CryptoStrategy(cryptoGateway)]
]),
transactionRepo,
notificationService
);
```
**Improvements**:
- Complexity: 15 → 3 (80% reduction)
- Open/Closed Principle: Add strategies without modifying processor
- Testability: Each strategy tested independently
- Maintainability: Clear separation of concerns
- Extensibility: Add new payment methods easily
---
### Pattern 3: Observer Pattern (Pub-Sub)
**Use when**:
- Multiple objects need to react to events
- Want loose coupling between components
- Need publish-subscribe event system
- State changes should notify dependents
**Before** (Tight coupling, manual notification):
```typescript
class UserService {
async createUser(data: CreateUserInput) {
const user = await this.db.users.create(data);
// Tightly coupled to all consumers
await this.emailService.sendWelcome(user);
await this.analyticsService.trackSignup(user);
await this.subscriptionService.createTrialSubscription(user);
await this.notificationService.sendAdminAlert(user);
await this.auditLogger.logUserCreated(user);
// Adding new consumer requires modifying this method
return user;
}
}
```
**After** (Observer Pattern):
```typescript
// events/EventEmitter.ts
type EventHandler<T = any> = (data: T) => Promise<void> | void;
export class EventEmitter {
private handlers: Map<string, EventHandler[]> = new Map();
on(event: string, handler: EventHandler): void {
if (!this.handlers.has(event)) {
this.handlers.set(event, []);
}
this.handlers.get(event)!.push(handler);
}
async emit(event: string, data: any): Promise<void> {
const handlers = this.handlers.get(event) || [];
await Promise.all(handlers.map(handler => handler(data)));
}
}
// events/UserEvents.ts
export const UserEvents = {
CREATED: 'user.created',
UPDATED: 'user.updated',
DELETED: 'user.deleted'
} as const;
// services/UserService.ts - Now decoupled
export class UserService {
constructor(
private db: Database,
private events: EventEmitter
) {}
async createUser(data: CreateUserInput): Promise<User> {
const user = await this.db.users.create(data);
// Simply publish event
await this.events.emit(UserEvents.CREATED, user);
return user;
}
}
// subscribers/WelcomeEmailSubscriber.ts
export class WelcomeEmailSubscriber {
constructor(
private emailService: EmailService,
private events: EventEmitter
) {
this.events.on(UserEvents.CREATED, this.handle.bind(this));
}
private async handle(user: User): Promise<void> {
await this.emailService.sendWelcome(user);
}
}
// subscribers/AnalyticsSubscriber.ts
export class AnalyticsSubscriber {
constructor(
private analyticsService: AnalyticsService,
private events: EventEmitter
) {
this.events.on(UserEvents.CREATED, this.handle.bind(this));
}
private async handle(user: User): Promise<void> {
await this.analyticsService.trackSignup(user);
}
}
// Setup
const events = new EventEmitter();
new WelcomeEmailSubscriber(emailService, events);
new AnalyticsSubscriber(analyticsService, events);
new SubscriptionSubscriber(subscriptionService, events);
new NotificationSubscriber(notificationService, events);
new AuditSubscriber(auditLogger, events);
const userService = new UserService(db, events);
```
**Improvements**:
- Loose coupling: UserService doesn't know about consumers
- Open/Closed: Add subscribers without modifying UserService
- Testability: Test UserService without dependencies
- Maintainability: Each subscriber isolated
- Flexibility: Enable/disable subscribers easily
---
### Pattern 4: Dependency Injection
**Use when**:
- Want to improve testability
- Need to swap implementations
- Want loose coupling
- Multiple dependencies
**Before** (Tight coupling, hard to test):
```typescript
class UserService {
private db = new Database(process.env.DB_URL!);
private emailService = new EmailService(process.env.SMTP_CONFIG!);
private logger = new Logger('UserService');
async createUser(data: CreateUserInput) {
this.logger.info('Creating user', data);
const user = await this.db.users.create(data);
await this.emailService.sendWelcome(user);
return user;
}
}
// Testing is painful - can't mock dependencies
test('createUser', async () => {
// Cannot inject test database or mock email service!
const service = new UserService();
// ...
});
```
**After** (Dependency Injection):
```typescript
// Define interfaces
interface IDatabase {
users: {
create(data: CreateUserData): Promise<User>;
findById(id: string): Promise<User | null>;
};
}
interface IEmailService {
sendWelcome(user: User): Promise<void>;
}
interface ILogger {
info(message: string, data?: any): void;
error(message: string, error?: Error): void;
}
// Inject dependencies
class UserService {
constructor(
private db: IDatabase,
private emailService: IEmailService,
private logger: ILogger
) {}
async createUser(data: CreateUserInput): Promise<User> {
this.logger.info('Creating user', data);
const user = await this.db.users.create(data);
await this.emailService.sendWelcome(user);
return user;
}
}
// Production setup
const db = new PostgresDatabase(config.database);
const emailService = new SMTPEmailService(config.smtp);
const logger = new WinstonLogger('UserService');
const userService = new UserService(db, emailService, logger);
// Test setup - Easy mocking!
test('createUser sends welcome email', async () => {
const mockDb = {
users: {
create: jest.fn().mockResolvedValue({ id: '1', email: 'test@example.com' })
}
};
const mockEmail = {
sendWelcome: jest.fn().mockResolvedValue(undefined)
};
const mockLogger = {
info: jest.fn(),
error: jest.fn()
};
const service = new UserService(mockDb, mockEmail, mockLogger);
await service.createUser({ email: 'test@example.com', name: 'Test' });
expect(mockEmail.sendWelcome).toHaveBeenCalledWith({ id: '1', email: 'test@example.com' });
});
```
**Improvements**:
- Testability: Easy to inject mocks
- Flexibility: Swap implementations (PostgreSQL → MongoDB)
- Loose coupling: Depends on interfaces, not implementations
- Clear dependencies: Constructor shows all dependencies
---
### Pattern 5: Repository Pattern
**Use when**:
- Want to abstract data access
- Need to swap data sources
- Want consistent query interface
- Separate domain from persistence
**Before** (Data access mixed with business logic):
```typescript
class UserService {
async getUsersByRole(role: string) {
// Direct database queries in service
const users = await prisma.user.findMany({
where: { role },
include: {
profile: true,
posts: { where: { published: true } }
}
});
return users;
}
async getActiveUsers() {
const users = await prisma.user.findMany({
where: { status: 'active', deletedAt: null }
});
return users;
}
// Many more methods with direct queries...
}
```
**After** (Repository Pattern):
```typescript
// repositories/UserRepository.ts
export interface IUserRepository {
findById(id: string): Promise<User | null>;
findByEmail(email: string): Promise<User | null>;
findByRole(role: string): Promise<User[]>;
findActive(): Promise<User[]>;
create(data: CreateUserData): Promise<User>;
update(id: string, data: Partial<User>): Promise<User>;
delete(id: string): Promise<void>;
}
export class PrismaUserRepository implements IUserRepository {
constructor(private prisma: PrismaClient) {}
async findById(id: string): Promise<User | null> {
return this.prisma.user.findUnique({
where: { id },
include: { profile: true }
});
}
async findByEmail(email: string): Promise<User | null> {
return this.prisma.user.findUnique({
where: { email },
include: { profile: true }
});
}
async findByRole(role: string): Promise<User[]> {
return this.prisma.user.findMany({
where: { role },
include: {
profile: true,
posts: { where: { published: true } }
}
});
}
async findActive(): Promise<User[]> {
return this.prisma.user.findMany({
where: { status: 'active', deletedAt: null }
});
}
async create(data: CreateUserData): Promise<User> {
return this.prisma.user.create({ data });
}
async update(id: string, data: Partial<User>): Promise<User> {
return this.prisma.user.update({ where: { id }, data });
}
async delete(id: string): Promise<void> {
await this.prisma.user.update({
where: { id },
data: { deletedAt: new Date() }
});
}
}
// services/UserService.ts - Clean business logic
export class UserService {
constructor(private userRepository: IUserRepository) {}
async getUsersByRole(role: string): Promise<User[]> {
return this.userRepository.findByRole(role);
}
async getActiveUsers(): Promise<User[]> {
return this.userRepository.findActive();
}
// Business logic, no persistence concerns
}
// Easy to swap data sources
class InMemoryUserRepository implements IUserRepository {
private users: Map<string, User> = new Map();
async findById(id: string): Promise<User | null> {
return this.users.get(id) || null;
}
// ... other methods using in-memory Map
}
// Testing with in-memory repository
test('getUsersByRole', async () => {
const repo = new InMemoryUserRepository();
await repo.create({ id: '1', email: 'admin@example.com', role: 'admin' });
const service = new UserService(repo);
const admins = await service.getUsersByRole('admin');
expect(admins).toHaveLength(1);
});
```
**Improvements**:
- Separation of concerns: Business logic separate from persistence
- Testability: Easy to use in-memory repository for tests
- Flexibility: Swap Prisma → TypeORM → MongoDB without changing services
- Consistency: Standardized query interface
- Caching: Easy to add caching layer in repository
---
### Pattern 6: Decorator Pattern
**Use when**:
- Want to add behavior dynamically
- Need multiple combinations of features
- Avoid subclass explosion
- Wrap functionality around core
**Before** (Subclass explosion):
```typescript
class Logger { log(message: string) { /* ... */ } }
class TimestampLogger extends Logger { /* adds timestamp */ }
class ColorLogger extends Logger { /* adds colors */ }
class FileLogger extends Logger { /* writes to file */ }
class TimestampColorLogger extends TimestampLogger { /* both timestamp and color */ }
class TimestampFileLogger extends TimestampLogger { /* both timestamp and file */ }
// Need class for every combination!
```
**After** (Decorator Pattern):
```typescript
// Core interface
interface Logger {
log(message: string): void;
}
// Base implementation
class ConsoleLogger implements Logger {
log(message: string): void {
console.log(message);
}
}
// Decorators
class TimestampDecorator implements Logger {
constructor(private logger: Logger) {}
log(message: string): void {
const timestamp = new Date().toISOString();
this.logger.log(`[${timestamp}] ${message}`);
}
}
class ColorDecorator implements Logger {
constructor(private logger: Logger, private color: string) {}
log(message: string): void {
this.logger.log(`\x1b[${this.color}m${message}\x1b[0m`);
}
}
class FileDecorator implements Logger {
constructor(private logger: Logger, private filePath: string) {}
log(message: string): void {
this.logger.log(message);
fs.appendFileSync(this.filePath, message + '\n');
}
}
// Compose decorators
let logger: Logger = new ConsoleLogger();
logger = new TimestampDecorator(logger);
logger = new ColorDecorator(logger, '32'); // green
logger = new FileDecorator(logger, './app.log');
logger.log('Hello World');
// Output: [2025-01-15T10:30:00.000Z] Hello World (in green, also in file)
```
**Improvements**:
- Flexibility: Mix and match decorators
- No subclass explosion: N decorators instead of 2^N classes
- Open/Closed: Add decorators without modifying logger
- Composition over inheritance
---
## Output Format
```markdown
# Design Pattern Introduction Report
## Pattern Applied: <pattern-name>
**Scope**: <path>
**Reason**: <motivation>
## Problem Statement
**Before**:
- <issue 1>
- <issue 2>
- <issue 3>
**Symptoms**:
- Complex conditional logic
- Tight coupling
- Difficult to test
- Hard to extend
## Solution: <Pattern Name>
**Benefits**:
- <benefit 1>
- <benefit 2>
- <benefit 3>
**Trade-offs**:
- <trade-off 1> (if any)
## Implementation
### Files Created
- <new-file-1>
- <new-file-2>
### Files Modified
- <modified-file-1>
- <modified-file-2>
### Code Changes
**Before**:
```typescript
<original-code>
```
**After**:
```typescript
<refactored-code-with-pattern>
```
## Verification
**Tests**:
- All existing tests: PASS
- New pattern tests: 12 added
- Coverage: 78% → 85%
**Metrics**:
- Complexity: 15 → 4 (73% improvement)
- Coupling: High → Low
- Extensibility: Improved
## Usage Guide
**How to use the new pattern**:
```typescript
<usage-example>
```
**How to extend**:
```typescript
<extension-example>
```
## Next Steps
**Additional Improvements**:
1. <next-opportunity>
2. <another-opportunity>
---
**Pattern Introduction Complete**: Code is now more flexible, testable, and maintainable.
```
## Error Handling
**Pattern not appropriate**:
```
Warning: <pattern> may not be the best solution for this problem.
Current problem: <description>
Suggested pattern: <alternative-pattern>
Reason: <explanation>
```
**Over-engineering risk**:
```
Warning: Introducing <pattern> may be over-engineering for current needs.
Current complexity: LOW
Pattern complexity: HIGH
Recommendation: Consider simpler solutions first:
1. Extract method/function
2. Use simple conditional
3. Wait until pattern truly needed (YAGNI)
```

243
commands/refactor/skill.md Normal file
View File

@@ -0,0 +1,243 @@
---
description: Comprehensive code refactoring operations for improving code quality and maintainability
---
# Code Refactoring Skill
You are executing a **code refactoring operation** to improve code quality, maintainability, and architecture without changing external behavior.
## Operation Routing
Parse `$ARGUMENTS` to identify the requested operation and parameters:
**Available Operations**:
- `analyze` → Analyze code quality and identify refactoring opportunities
- `extract` → Extract methods, classes, modules, or components
- `patterns` → Introduce design patterns (Factory, Strategy, Observer, etc.)
- `types` → Improve type safety (TypeScript)
- `duplicate` → Eliminate code duplication
- `modernize` → Update legacy code patterns
**Base Directory**: `/home/danie/projects/plugins/architect/open-plugins/plugins/10x-fullstack-engineer/commands/refactor`
## Request Processing
**Received**: `$ARGUMENTS`
**Parse format**:
```
<operation> <parameters>
```
Example arguments:
- `analyze scope:"user authentication module" metrics:"complexity,duplication" depth:"detailed"`
- `extract scope:"UserProfile.tsx" type:"method" target:"validateEmail" reason:"reduce complexity"`
- `patterns scope:"services/" pattern:"dependency-injection" reason:"improve testability"`
- `types scope:"api-client/" strategy:"eliminate-any" strict:"true"`
- `duplicate scope:"src/validators" threshold:"80" strategy:"extract-function"`
- `modernize scope:"legacy-api/" targets:"callbacks-to-async,classes-to-hooks"`
## Pre-Refactoring Safety Checklist
**CRITICAL**: Before ANY refactoring, verify:
1. **Test Coverage**:
- Existing test coverage is adequate (>70% for code being refactored)
- All tests currently passing
- Tests are meaningful and test behavior, not implementation
2. **Version Control**:
- All changes committed to version control
- Working on a feature branch (not main/master)
- Clean working directory (no uncommitted changes)
3. **Backup**:
- Current state committed with clear message
- Can easily revert if needed
- Branch created specifically for this refactoring
4. **Scope Definition**:
- Clearly defined boundaries of what to refactor
- No mixing of refactoring with new features
- Reasonable size for one refactoring session
5. **Risk Assessment**:
- Understand dependencies and impact
- Identify potential breaking changes
- Have rollback plan ready
## Operation Execution
Based on the first word in `$ARGUMENTS`, execute the corresponding operation:
### If operation is "analyze":
Read and execute: `.claude/commands/refactor/analyze.md`
**Purpose**: Analyze code quality, identify code smells, calculate metrics, prioritize refactoring opportunities.
### If operation is "extract":
Read and execute: `.claude/commands/refactor/extract.md`
**Purpose**: Extract methods, classes, modules, components, utilities, or interfaces to improve code organization.
### If operation is "patterns":
Read and execute: `.claude/commands/refactor/patterns.md`
**Purpose**: Introduce design patterns (Factory, Strategy, Observer, Dependency Injection, Repository, etc.) to solve recurring design problems.
### If operation is "types":
Read and execute: `.claude/commands/refactor/types.md`
**Purpose**: Improve type safety by adding types, strengthening types, migrating to TypeScript, eliminating 'any', or adding generics.
### If operation is "duplicate":
Read and execute: `.claude/commands/refactor/duplicate.md`
**Purpose**: Detect and eliminate code duplication through extraction, parameterization, or templating.
### If operation is "modernize":
Read and execute: `.claude/commands/refactor/modernize.md`
**Purpose**: Update legacy code patterns (callbacks→async/await, var→const/let, prototypes→classes, CommonJS→ESM, jQuery→vanilla, classes→hooks).
### If operation is unknown or missing:
Provide operation list and usage examples.
## Error Handling
**Unknown Operation**:
```
Error: Unknown refactoring operation: <operation>
Available operations:
- analyze - Analyze code quality and identify opportunities
- extract - Extract methods, classes, modules, components
- patterns - Introduce design patterns
- types - Improve type safety (TypeScript)
- duplicate - Eliminate code duplication
- modernize - Update legacy code patterns
Usage: /refactor <operation> <parameters>
Examples:
/refactor analyze scope:"user-service/" depth:"detailed"
/refactor extract scope:"UserForm.tsx" type:"component" target:"EmailInput"
/refactor patterns scope:"services/" pattern:"dependency-injection"
```
**Missing Parameters**:
```
Error: Required parameters missing for <operation>
Expected format: /refactor <operation> scope:"..." [additional-params]
See: /refactor <operation> help
```
**Insufficient Test Coverage**:
```
Warning: Test coverage is below recommended threshold (<70%).
Recommendations:
1. Add tests for code being refactored
2. Reduce refactoring scope to well-tested areas
3. Write tests first, then refactor (Red-Green-Refactor)
Continue anyway? This increases risk of breaking changes.
```
**Uncommitted Changes**:
```
Error: Working directory has uncommitted changes.
Refactoring requires clean version control state for safety.
Action required:
1. Commit current changes: git add . && git commit -m "..."
2. Or stash changes: git stash
3. Create feature branch: git checkout -b refactor/<description>
Then retry refactoring operation.
```
## Integration with 10x-fullstack-engineer Agent
All refactoring operations leverage the **10x-fullstack-engineer** agent for:
- Expert code quality analysis
- Best practice application
- Pattern recognition and recommendation
- Consistency with project standards
- Risk assessment and mitigation
- Test-driven refactoring approach
The agent applies SOLID principles, DRY, YAGNI, and follows the Boy Scout Rule (leave code better than found).
## Refactoring Principles
All operations adhere to:
1. **Preserve Behavior**: External behavior must remain unchanged
2. **Small Steps**: Incremental changes with frequent testing
3. **Test-Driven**: Tests pass before, during, and after refactoring
4. **One Thing at a Time**: Don't mix refactoring with feature development
5. **Frequent Commits**: Commit after each successful refactoring step
6. **Clear Intent**: Each change has clear purpose and benefit
7. **Reversibility**: Easy to revert if something goes wrong
8. **Maintainability First**: Optimize for readability and maintainability
## Usage Examples
**Analyze codebase for refactoring opportunities**:
```bash
/refactor analyze scope:"src/components" metrics:"complexity,duplication,coverage" depth:"detailed"
```
**Extract long method into smaller functions**:
```bash
/refactor extract scope:"UserService.ts" type:"method" target:"validateAndCreateUser" reason:"function is 150 lines, too complex"
```
**Introduce dependency injection pattern**:
```bash
/refactor patterns scope:"services/" pattern:"dependency-injection" reason:"improve testability and flexibility"
```
**Strengthen TypeScript type safety**:
```bash
/refactor types scope:"api/" strategy:"eliminate-any" strict:"true"
```
**Eliminate duplicate validation logic**:
```bash
/refactor duplicate scope:"src/validators" threshold:"75" strategy:"extract-function"
```
**Modernize legacy callback code to async/await**:
```bash
/refactor modernize scope:"legacy-api/" targets:"callbacks-to-async" compatibility:"node14+"
```
## Best Practices
1. **Start Small**: Begin with low-risk, high-value refactorings
2. **Test Continuously**: Run tests after each change
3. **Commit Frequently**: Small commits with clear messages
4. **Pair Review**: Have someone review refactored code
5. **Measure Impact**: Track metrics before and after
6. **Document Why**: Explain reasoning in commits and comments
7. **Avoid Scope Creep**: Stay focused on defined scope
8. **Time Box**: Set time limits for refactoring sessions
## Output
All operations provide detailed reports including:
- Before/after code examples
- Metrics improvement (complexity, coverage, duplication)
- Changes made and reasoning
- Verification steps
- Future refactoring opportunities
- Risk assessment and mitigation
---
**Ready to refactor**: Specify operation and parameters to begin.

896
commands/refactor/types.md Normal file
View File

@@ -0,0 +1,896 @@
# Type Safety Improvement Operation
Improve TypeScript type safety by adding types, strengthening existing types, migrating to TypeScript, eliminating 'any', or adding generics.
## Parameters
**Received from $ARGUMENTS**: All arguments after "types"
**Expected format**:
```
scope:"<path>" strategy:"<strategy-name>" [strict:"true|false"]
```
**Parameter definitions**:
- `scope` (REQUIRED): Path to improve (e.g., "src/api/", "utils/helpers.ts")
- `strategy` (REQUIRED): Type improvement strategy
- `add-types` - Add missing type annotations
- `strengthen-types` - Replace weak types with specific ones
- `migrate-to-ts` - Convert JavaScript to TypeScript
- `eliminate-any` - Remove 'any' types
- `add-generics` - Add generic type parameters
- `strict` (OPTIONAL): Enable strict TypeScript mode (default: false)
## Workflow
### 1. TypeScript Configuration Check
Verify TypeScript setup:
```bash
# Check if TypeScript is configured
test -f tsconfig.json || echo "No tsconfig.json found"
# Check current strictness
cat tsconfig.json | grep -A5 "compilerOptions"
# Type check current state
npx tsc --noEmit
```
### 2. Analyze Type Coverage
Assess current type safety:
```bash
# Count 'any' usage
grep -r "any" <scope> --include="*.ts" --include="*.tsx" | wc -l
# Count implicit any
npx tsc --noEmit --noImplicitAny 2>&1 | grep "implicitly has an 'any' type" | wc -l
# Check for type assertions
grep -r "as any" <scope> --include="*.ts" --include="*.tsx"
```
## Strategy Examples
### Strategy 1: Add Missing Types
**Before** (Missing types):
```typescript
// utils/helpers.ts
export function formatDate(date) {
return date.toISOString().split('T')[0];
}
export function calculateTotal(items) {
return items.reduce((sum, item) => sum + item.price, 0);
}
export async function fetchUser(id) {
const response = await fetch(`/api/users/${id}`);
return response.json();
}
export function createUser(name, email, age) {
return {
id: generateId(),
name,
email,
age,
createdAt: new Date()
};
}
```
**After** (Full type annotations):
```typescript
// utils/helpers.ts
export function formatDate(date: Date): string {
return date.toISOString().split('T')[0];
}
interface Item {
price: number;
name: string;
}
export function calculateTotal(items: Item[]): number {
return items.reduce((sum, item) => sum + item.price, 0);
}
interface User {
id: string;
name: string;
email: string;
age: number;
createdAt: Date;
}
export async function fetchUser(id: string): Promise<User> {
const response = await fetch(`/api/users/${id}`);
return response.json() as User;
}
export function createUser(
name: string,
email: string,
age: number
): User {
return {
id: generateId(),
name,
email,
age,
createdAt: new Date()
};
}
```
**Improvements**:
- Catch type errors at compile time
- Better IDE autocomplete
- Self-documenting code
- Refactoring safety
---
### Strategy 2: Strengthen Types (Eliminate 'any')
**Before** (Weak 'any' types):
```typescript
// api/client.ts
class APIClient {
async get(endpoint: string): Promise<any> {
const response = await fetch(endpoint);
return response.json();
}
async post(endpoint: string, data: any): Promise<any> {
const response = await fetch(endpoint, {
method: 'POST',
body: JSON.stringify(data)
});
return response.json();
}
handleError(error: any) {
console.error(error);
}
}
// Usage - No type safety!
const user = await client.get('/users/1');
console.log(user.nameeee); // Typo not caught!
```
**After** (Strong specific types):
```typescript
// types/api.ts
export interface User {
id: string;
name: string;
email: string;
role: 'admin' | 'user';
}
export interface Post {
id: string;
title: string;
content: string;
authorId: string;
}
export interface APIError {
code: string;
message: string;
details?: Record<string, string[]>;
}
// api/client.ts
class APIClient {
async get<T>(endpoint: string): Promise<T> {
const response = await fetch(endpoint);
if (!response.ok) {
throw await this.handleError(response);
}
return response.json() as T;
}
async post<TRequest, TResponse>(
endpoint: string,
data: TRequest
): Promise<TResponse> {
const response = await fetch(endpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
if (!response.ok) {
throw await this.handleError(response);
}
return response.json() as TResponse;
}
private async handleError(response: Response): Promise<APIError> {
const error: APIError = await response.json();
console.error('API Error:', error);
return error;
}
}
// Usage - Full type safety!
const user = await client.get<User>('/users/1');
console.log(user.name); // Autocomplete works!
console.log(user.nameeee); // Error: Property 'nameeee' does not exist
const newPost = await client.post<CreatePostInput, Post>('/posts', {
title: 'Hello',
content: 'World'
});
```
**Improvements**:
- Eliminate all 'any' types
- Generic type parameters for flexibility
- Catch typos at compile time
- Better developer experience
---
### Strategy 3: Add Generics
**Before** (Type repetition, limited reusability):
```typescript
// Without generics - Need separate class for each type
class UserRepository {
private users: User[] = [];
add(user: User): void {
this.users.push(user);
}
findById(id: string): User | undefined {
return this.users.find(u => u.id === id);
}
findAll(): User[] {
return [...this.users];
}
remove(id: string): boolean {
const index = this.users.findIndex(u => u.id === id);
if (index > -1) {
this.users.splice(index, 1);
return true;
}
return false;
}
}
class PostRepository {
private posts: Post[] = [];
add(post: Post): void {
this.posts.push(post);
}
findById(id: string): Post | undefined {
return this.posts.find(p => p.id === id);
}
findAll(): Post[] {
return [...this.posts];
}
remove(id: string): boolean {
const index = this.posts.findIndex(p => p.id === id);
if (index > -1) {
this.posts.splice(index, 1);
return true;
}
return false;
}
}
// Need duplicate class for each entity type!
```
**After** (Generic repository - DRY):
```typescript
// Generic base repository
interface Entity {
id: string;
}
class Repository<T extends Entity> {
private items: Map<string, T> = new Map();
add(item: T): void {
this.items.set(item.id, item);
}
findById(id: string): T | undefined {
return this.items.get(id);
}
findAll(): T[] {
return Array.from(this.items.values());
}
findBy(predicate: (item: T) => boolean): T[] {
return this.findAll().filter(predicate);
}
update(id: string, updates: Partial<T>): T | undefined {
const item = this.items.get(id);
if (item) {
const updated = { ...item, ...updates };
this.items.set(id, updated);
return updated;
}
return undefined;
}
remove(id: string): boolean {
return this.items.delete(id);
}
count(): number {
return this.items.size;
}
}
// Usage with specific types
interface User extends Entity {
name: string;
email: string;
}
interface Post extends Entity {
title: string;
content: string;
authorId: string;
}
const userRepo = new Repository<User>();
const postRepo = new Repository<Post>();
// Full type safety
userRepo.add({ id: '1', name: 'John', email: 'john@example.com' });
const user = userRepo.findById('1'); // Type: User | undefined
const admins = userRepo.findBy(u => u.email.endsWith('@admin.com')); // Type: User[]
postRepo.add({ id: '1', title: 'Hello', content: 'World', authorId: '1' });
const post = postRepo.findById('1'); // Type: Post | undefined
```
**More generic examples**:
```typescript
// Generic API response wrapper
interface APIResponse<T> {
data: T;
status: number;
message: string;
}
async function fetchData<T>(url: string): Promise<APIResponse<T>> {
const response = await fetch(url);
return response.json();
}
// Usage
const userResponse = await fetchData<User>('/api/user');
const users = userResponse.data; // Type: User
// Generic event emitter
class EventEmitter<TEvents extends Record<string, any>> {
private handlers: Partial<{
[K in keyof TEvents]: Array<(data: TEvents[K]) => void>;
}> = {};
on<K extends keyof TEvents>(
event: K,
handler: (data: TEvents[K]) => void
): void {
if (!this.handlers[event]) {
this.handlers[event] = [];
}
this.handlers[event]!.push(handler);
}
emit<K extends keyof TEvents>(event: K, data: TEvents[K]): void {
const handlers = this.handlers[event] || [];
handlers.forEach(handler => handler(data));
}
}
// Usage with typed events
interface AppEvents {
'user:login': { userId: string; timestamp: Date };
'user:logout': { userId: string };
'post:created': { postId: string; authorId: string };
}
const emitter = new EventEmitter<AppEvents>();
emitter.on('user:login', (data) => {
// data is typed as { userId: string; timestamp: Date }
console.log(`User ${data.userId} logged in at ${data.timestamp}`);
});
emitter.emit('user:login', {
userId: '123',
timestamp: new Date()
}); // Type safe!
// This would error:
// emitter.emit('user:login', { userId: 123 }); // Error: number not assignable to string
```
**Improvements**:
- DRY: Single implementation for all types
- Type safety: Generic constraints ensure correctness
- Reusability: Works with any type that extends Entity
- Maintainability: Fix bugs once, benefits all uses
---
### Strategy 4: Migrate JavaScript to TypeScript
**Before** (JavaScript with no types):
```javascript
// user-service.js
const bcrypt = require('bcrypt');
class UserService {
constructor(database, emailService) {
this.db = database;
this.emailService = emailService;
}
async registerUser(userData) {
// Validate email
if (!userData.email || !userData.email.includes('@')) {
throw new Error('Invalid email');
}
// Check if user exists
const existing = await this.db.users.findOne({ email: userData.email });
if (existing) {
throw new Error('User already exists');
}
// Hash password
const hashedPassword = await bcrypt.hash(userData.password, 10);
// Create user
const user = await this.db.users.create({
email: userData.email,
password: hashedPassword,
name: userData.name,
createdAt: new Date()
});
// Send welcome email
await this.emailService.sendWelcome(user.email);
return {
id: user.id,
email: user.email,
name: user.name
};
}
async login(email, password) {
const user = await this.db.users.findOne({ email });
if (!user) {
throw new Error('Invalid credentials');
}
const passwordMatch = await bcrypt.compare(password, user.password);
if (!passwordMatch) {
throw new Error('Invalid credentials');
}
return {
id: user.id,
email: user.email,
name: user.name
};
}
}
module.exports = UserService;
```
**After** (TypeScript with full types):
```typescript
// types/user.ts
export interface User {
id: string;
email: string;
password: string;
name: string;
createdAt: Date;
updatedAt: Date;
}
export interface CreateUserInput {
email: string;
password: string;
name: string;
}
export interface UserDTO {
id: string;
email: string;
name: string;
}
export interface LoginCredentials {
email: string;
password: string;
}
// types/database.ts
export interface IDatabase {
users: {
findOne(query: { email: string }): Promise<User | null>;
create(data: Omit<User, 'id' | 'updatedAt'>): Promise<User>;
};
}
// types/email.ts
export interface IEmailService {
sendWelcome(email: string): Promise<void>;
}
// user-service.ts
import * as bcrypt from 'bcrypt';
import {
User,
CreateUserInput,
UserDTO,
LoginCredentials
} from './types/user';
import { IDatabase } from './types/database';
import { IEmailService } from './types/email';
export class UserService {
constructor(
private readonly db: IDatabase,
private readonly emailService: IEmailService
) {}
async registerUser(userData: CreateUserInput): Promise<UserDTO> {
// Validate email
this.validateEmail(userData.email);
// Check if user exists
const existing = await this.db.users.findOne({ email: userData.email });
if (existing) {
throw new UserAlreadyExistsError(userData.email);
}
// Hash password
const hashedPassword = await bcrypt.hash(userData.password, 10);
// Create user
const user = await this.db.users.create({
email: userData.email,
password: hashedPassword,
name: userData.name,
createdAt: new Date()
});
// Send welcome email
await this.emailService.sendWelcome(user.email);
return this.toDTO(user);
}
async login(credentials: LoginCredentials): Promise<UserDTO> {
const user = await this.db.users.findOne({ email: credentials.email });
if (!user) {
throw new InvalidCredentialsError();
}
const passwordMatch = await bcrypt.compare(
credentials.password,
user.password
);
if (!passwordMatch) {
throw new InvalidCredentialsError();
}
return this.toDTO(user);
}
private validateEmail(email: string): void {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) {
throw new InvalidEmailError(email);
}
}
private toDTO(user: User): UserDTO {
return {
id: user.id,
email: user.email,
name: user.name
};
}
}
// Custom error classes with types
export class UserAlreadyExistsError extends Error {
constructor(email: string) {
super(`User with email ${email} already exists`);
this.name = 'UserAlreadyExistsError';
}
}
export class InvalidCredentialsError extends Error {
constructor() {
super('Invalid credentials');
this.name = 'InvalidCredentialsError';
}
}
export class InvalidEmailError extends Error {
constructor(email: string) {
super(`Invalid email format: ${email}`);
this.name = 'InvalidEmailError';
}
}
```
**Migration steps**:
1. Rename `.js` to `.ts`
2. Add interface definitions
3. Add type annotations to parameters and return types
4. Replace `require()` with `import`
5. Replace `module.exports` with `export`
6. Add custom error classes with types
7. Extract utility functions with proper types
8. Fix all TypeScript errors
9. Enable strict mode gradually
**Improvements**:
- Full compile-time type checking
- Better refactoring support
- Self-documenting code
- Catch errors before runtime
- Modern ES6+ features
---
### Strategy 5: Enable Strict Mode
**Before** (tsconfig.json - Lenient):
```json
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"strict": false,
"esModuleInterop": true
}
}
```
**After** (tsconfig.json - Strict):
```json
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
/* Strict Type-Checking Options */
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictBindCallApply": true,
"strictPropertyInitialization": true,
"noImplicitThis": true,
"alwaysStrict": true,
/* Additional Checks */
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedIndexedAccess": true,
/* Module Resolution */
"esModuleInterop": true,
"skipLibCheck": false,
"forceConsistentCasingInFileNames": true
}
}
```
**Impact of strict mode**:
```typescript
// Before: Implicit any allowed
function process(data) { // No error
return data.value;
}
// After: Must specify types
function process(data: DataInput): number { // Required
return data.value;
}
// Before: Null not checked
function getUser(id: string): User {
return database.findById(id); // Could be null!
}
// After: Must handle null
function getUser(id: string): User | null {
return database.findById(id);
}
const user = getUser('123');
console.log(user.name); // Error: Object is possibly 'null'
// Must check:
if (user) {
console.log(user.name); // OK
}
// Or use optional chaining:
console.log(user?.name); // OK
// Before: Array access unchecked
const users: User[] = [];
const first = users[0]; // Type: User (wrong! could be undefined)
first.email; // Runtime error if array is empty
// After: Array access checked
const users: User[] = [];
const first = users[0]; // Type: User | undefined (correct!)
first.email; // Error: Object is possibly 'undefined'
// Must check:
if (first) {
first.email; // OK
}
```
**Improvements**:
- Catch more errors at compile time
- Safer null/undefined handling
- No implicit any types
- More robust code
- Better IDE support
---
## Output Format
```markdown
# Type Safety Improvement Report
## Strategy Applied: <strategy-name>
**Scope**: <path>
**Strict Mode**: <enabled/disabled>
## Before
**Type Coverage**:
- Files with types: <count> / <total> (<percentage>%)
- 'any' usage: <count> instances
- Implicit any: <count> instances
- Type errors: <count>
**Issues**:
- <issue 1>
- <issue 2>
## Changes Made
### Files Modified
- <file-1>: Added type annotations
- <file-2>: Eliminated 'any' types
- <file-3>: Migrated JS to TS
### Type Definitions Added
```typescript
<new-interfaces-and-types>
```
### Code Examples
**Before**:
```typescript
<code-without-types>
```
**After**:
```typescript
<code-with-types>
```
## After
**Type Coverage**:
- Files with types: <count> / <total> (<percentage>%)
- 'any' usage: <count> instances (<percentage>% reduction)
- Implicit any: 0 (eliminated)
- Type errors: 0 (all fixed)
**Improvements**:
- Type safety: <before>% → <after>%
- Compile-time error detection: +<count> errors caught
- IDE autocomplete: Significantly improved
- Refactoring safety: Enhanced
## Verification
**Type Check**:
```bash
npx tsc --noEmit
# No errors
```
**Tests**:
- All tests passing: YES
- Coverage: <before>% → <after>%
## Migration Guide
**For Consumers**:
```typescript
// Old usage (if breaking changes)
<old-usage>
// New usage
<new-usage>
```
## Next Steps
**Additional Improvements**:
1. Enable stricter compiler options
2. Add runtime type validation (Zod, io-ts)
3. Generate types from API schemas
4. Add JSDoc for better documentation
---
**Type Safety Improved**: Code is now safer and more maintainable.
```
## Error Handling
**No TypeScript configuration**:
```
Error: No tsconfig.json found in project
To use this operation, initialize TypeScript:
1. npm install -D typescript
2. npx tsc --init
3. Configure tsconfig.json
4. Retry operation
```
**Too many type errors**:
```
Warning: Found <count> type errors. This is a large migration.
Recommendation: Gradual migration approach:
1. Start with strict: false
2. Fix implicit any errors first
3. Enable strictNullChecks
4. Enable other strict options one by one
5. Fix errors incrementally
```