Automatically fix ESLint violations across your codebase using Droid Exec
This tutorial demonstrates how to use Droid Exec to automatically fix ESLint violations across your codebase. The script identifies files with lint errors and intelligently fixes them while preserving functionality.
This approach works with any ESLint rule - from simple formatting issues to complex architectural patterns.
#!/bin/bash# Droid Route Middleware Fix Script# Automatically adds required middleware to NextJS API routes that are missing them## Usage: ./droid-fix-route-middleware.sh [directory]# Example: ./droid-fix-route-middleware.sh apps/factory-appset -e# ConfigurationCONCURRENCY=${CONCURRENCY:-5}DRY_RUN=${DRY_RUN:-false}TARGET_DIR="${1:-.}"ESLINT_RULE="factory/require-route-middleware"# Colors for outputGREEN='\033[0;32m'YELLOW='\033[1;33m'BLUE='\033[0;34m'RED='\033[0;31m'NC='\033[0m'# Temp files for trackingTEMP_DIR=$(mktemp -d)VIOLATIONS_FILE="$TEMP_DIR/violations.txt"PROCESSED_COUNT=0FIXED_COUNT=0FAILED_COUNT=0# Cleanup on exittrap "rm -rf $TEMP_DIR" EXIT# Function to detect violations using ESLintfind_violations() { echo -e "${BLUE}Scanning for route middleware violations...${NC}" # Run ESLint with the specific rule and capture violations # Using --format json for easier parsing npx eslint "$TARGET_DIR" \ --ext .ts,.tsx \ --rule "${ESLINT_RULE}: error" \ --format json 2>/dev/null | \ jq -r '.[] | select(.errorCount > 0) | .filePath' > "$VIOLATIONS_FILE" || true # Alternative approach if the above doesn't work - find all route.ts files # and check them individually if [ ! -s "$VIOLATIONS_FILE" ]; then find "$TARGET_DIR" -type f -name "route.ts" \ ! -path "*/node_modules/*" \ ! -path "*/.next/*" \ ! -path "*/dist/*" \ ! -path "*/build/*" | while read -r file; do # Check if file has middleware violations if npx eslint "$file" \ --rule "${ESLINT_RULE}: error" \ --format compact 2>&1 | grep -q "require-route-middleware"; then echo "$file" >> "$VIOLATIONS_FILE" fi done fi}# Function to determine the appropriate middleware type based on route pathget_middleware_type() { local filepath="$1" # Check for specific route patterns if [[ "$filepath" == *"/api/cron/"* ]]; then echo "cron" elif [[ "$filepath" == *"/api/webhooks/"* ]]; then echo "public" elif [[ "$filepath" == *"/api/admin/"* ]]; then echo "admin" elif [[ "$filepath" == *"/api/auth/"* ]] && [[ "$filepath" != *"/logout"* ]]; then echo "public" elif [[ "$filepath" == *"/api/health"* ]] || [[ "$filepath" == *"/api/echo"* ]]; then echo "public" elif [[ "$filepath" == *"factory-admin"* ]]; then echo "admin" else echo "authenticated" fi}# Function to process a single fileprocess_file() { local filepath="$1" local filename=$(basename "$filepath") local middleware_type=$(get_middleware_type "$filepath") echo -e "${BLUE}Processing: $filepath${NC}" echo -e " Detected type: $middleware_type middleware needed" # The AI prompt for adding middleware local prompt="Fix the middleware violations in $filepath by adding the appropriate middleware handler.IMPORTANT CONTEXT:This is a NextJS API route file that needs middleware added to each exported HTTP handler (GET, POST, PUT, DELETE, etc.).The middleware must be the FIRST statement in each handler function.Based on the route type ($middleware_type), use the appropriate middleware:1. For 'authenticated' routes (require user login):\`\`\`typescriptimport { handleAuthenticatedMiddleware } from '@/app/api/_utils/middleware';export async function GET(req: NextRequest) { return handleAuthenticatedMiddleware(req, async ({ req, user }) => { // Existing route logic here // 'user' is the authenticated UserRecord return NextResponse.json({ data }); });}\`\`\`2. For 'public' routes (no auth required):\`\`\`typescriptimport { handlePublicMiddleware } from '@/app/api/_utils/middleware';export async function POST(req: NextRequest) { return handlePublicMiddleware(req, async (req) => { // Existing route logic here return NextResponse.json({ data }); });}\`\`\`3. For 'cron' routes (require cron secret):\`\`\`typescriptimport { handleCronMiddleware } from '@/app/api/_utils/middleware';export async function POST(req: NextRequest) { return handleCronMiddleware(req, async (req) => { // Existing route logic here return NextResponse.json({ success: true }); });}\`\`\`4. For 'admin' routes (require admin role):\`\`\`typescriptimport { handleAuthenticatedMiddleware, AdminRole } from '@/app/api/_utils/middleware';export async function GET(req: NextRequest) { return handleAuthenticatedMiddleware( req, async ({ req, user }) => { // Existing route logic here return NextResponse.json({ data }); }, { requiredRole: AdminRole.ADMIN_1 } );}\`\`\`Additional options can be passed:- \`context\`: String for error logging context- \`requireCsrf\`: Boolean to enable CSRF validation- \`requiredRole\`: AdminRole enum value for role-based accessINSTRUCTIONS:1. Add the appropriate import for the middleware function if not present2. Wrap the ENTIRE body of each exported HTTP handler with the middleware call3. The middleware should return the result of the middleware function4. Move ALL existing logic inside the middleware callback5. Preserve all existing imports, types, and logic exactly as-is6. If the handler already uses try-catch for error handling, you can remove it as the middleware handles errors7. Ensure the callback parameters match the middleware type (some provide 'user', others just 'req')Only modify the route handlers to add middleware. Return the complete fixed file." if [ "$DRY_RUN" = "true" ]; then echo -e "${YELLOW} [DRY RUN] Would add $middleware_type middleware${NC}" return 0 fi # Run droid to fix the middleware if droid exec --auto low "$prompt" 2>/dev/null; then # Verify the fix worked by running ESLint again if npx eslint "$filepath" \ --rule "${ESLINT_RULE}: error" \ --no-eslintrc \ --plugin factory \ --format compact 2>&1 | grep -q "require-route-middleware"; then echo -e "${RED} ✗ Failed to fix all violations${NC}" ((FAILED_COUNT++)) else echo -e "${GREEN} ✓ Fixed middleware violations${NC}" ((FIXED_COUNT++)) fi ((PROCESSED_COUNT++)) else echo -e "${RED} ✗ Failed to process${NC}" ((FAILED_COUNT++)) fi}# Export function and variables for parallel executionexport -f process_file get_middleware_typeexport DRY_RUN GREEN YELLOW BLUE RED NC ESLINT_RULE# Main executionecho -e "${BLUE}=== Droid Route Middleware Fix ===${NC}"echo -e "${BLUE}Directory: $TARGET_DIR${NC}"echo -e "${BLUE}Concurrency: $CONCURRENCY${NC}"[ "$DRY_RUN" = "true" ] && echo -e "${YELLOW}DRY RUN MODE${NC}"echo ""# Find violationsfind_violationsVIOLATION_COUNT=$(wc -l < "$VIOLATIONS_FILE" 2>/dev/null | tr -d ' ' || echo 0)if [ "$VIOLATION_COUNT" -eq 0 ]; then echo -e "${GREEN}No middleware violations found!${NC}" exit 0fiecho -e "${YELLOW}Found $VIOLATION_COUNT files with middleware violations${NC}\n"# Process files in parallelcat "$VIOLATIONS_FILE" | xargs -n 1 -P "$CONCURRENCY" -I {} bash -c 'process_file "$@"' _ {}# Show summaryecho -e "\n${BLUE}=== Summary ===${NC}"echo -e "${GREEN}Files processed: $PROCESSED_COUNT${NC}"if [ "$DRY_RUN" = "false" ]; then echo -e "${GREEN}Files fixed: $FIXED_COUNT${NC}" [ "$FAILED_COUNT" -gt 0 ] && echo -e "${RED}Files failed: $FAILED_COUNT${NC}"fiif [ "$DRY_RUN" = "false" ] && [ "$FIXED_COUNT" -gt 0 ]; then echo -e "\n${BLUE}Next steps:${NC}" echo " npm run lint # Verify all violations are fixed" echo " npm run typecheck # Check TypeScript compilation" echo " npm run test # Run tests" echo " git diff # Review changes" echo " git add -A # Stage changes" echo " git commit -m 'fix: add required middleware to API routes'"fi# Exit with error if some files failed[ "$FAILED_COUNT" -gt 0 ] && exit 1exit 0
Critical for Success: When customizing this script for your own lint rules, always include concrete before/after examples in the prompt you give to Droid Exec. This dramatically improves accuracy.Good prompt structure:
Describe the violation to fix
Show a “before” code example with the violation
Show an “after” code example with the fix applied
List any edge cases or patterns to preserve
The more specific your examples, the better Droid will understand and implement the fix pattern.