Advertisement

← claude-skills

deslop/scripts/scan_dead_code.sh

4.0 KB Download file
#!/bin/bash
# scan_dead_code.sh — Detect likely dead code in a codebase
# Usage: bash scan_dead_code.sh [directory]
#
# Outputs a list of potential dead code candidates. NOT definitive —
# dynamic imports, reflection, and framework magic can cause false positives.
# The LLM should review each candidate for false positives before flagging.

DIR="${1:-.}"
echo "=== Dead Code Scan: $DIR ==="
echo ""

# --- Unused exports (JS/TS) ---
echo "## Potentially unused exported functions (JS/TS)"
echo "# Functions defined with 'export' but not imported elsewhere"
echo ""

for f in $(find "$DIR" -name "*.js" -o -name "*.ts" -o -name "*.tsx" -o -name "*.jsx" 2>/dev/null | grep -v node_modules | grep -v dist | grep -v build | grep -v ".d.ts"); do
    # Extract exported function/const names
    grep -oP '(?<=export (?:function|const|class|let|var|async function) )\w+' "$f" 2>/dev/null | while read -r name; do
        # Count references in other files (exclude the defining file itself)
        count=$(grep -rn --include="*.js" --include="*.ts" --include="*.tsx" --include="*.jsx" "$name" "$DIR" 2>/dev/null | grep -v node_modules | grep -v "$f" | wc -l)
        if [ "$count" -eq "0" ]; then
            echo "  UNUSED_EXPORT: $name in $f"
        fi
    done
done

echo ""

# --- Unused Python functions ---
echo "## Potentially unused functions (Python)"
echo ""

for f in $(find "$DIR" -name "*.py" 2>/dev/null | grep -v __pycache__ | grep -v venv | grep -v .venv | grep -v site-packages); do
    grep -oP '(?<=def )\w+' "$f" 2>/dev/null | while read -r name; do
        # Skip dunder methods, test functions, and private methods
        if [[ "$name" == __* ]] || [[ "$name" == test_* ]] || [[ "$name" == _* ]]; then
            continue
        fi
        count=$(grep -rn --include="*.py" "$name" "$DIR" 2>/dev/null | grep -v __pycache__ | grep -v venv | grep -v "$f:" | wc -l)
        if [ "$count" -eq "0" ]; then
            echo "  UNUSED_FUNC: $name in $f"
        fi
    done
done

echo ""

# --- Unused imports ---
echo "## Unused imports"
echo ""

# JS/TS: imported names not referenced later in the same file
for f in $(find "$DIR" -name "*.js" -o -name "*.ts" -o -name "*.tsx" -o -name "*.jsx" 2>/dev/null | grep -v node_modules | grep -v dist | grep -v build); do
    grep -oP "import\s+\{([^}]+)\}" "$f" 2>/dev/null | grep -oP '\w+' | while read -r name; do
        # Skip 'import' and 'from' keywords
        if [[ "$name" == "import" ]] || [[ "$name" == "from" ]]; then continue; fi
        count=$(grep -c "$name" "$f" 2>/dev/null)
        if [ "$count" -le "1" ]; then
            echo "  UNUSED_IMPORT: $name in $f"
        fi
    done
done

echo ""

# --- Commented-out code blocks ---
echo "## Large commented-out code blocks (>3 lines)"
echo ""

for f in $(find "$DIR" \( -name "*.js" -o -name "*.ts" -o -name "*.py" -o -name "*.java" -o -name "*.go" -o -name "*.rb" \) 2>/dev/null | grep -v node_modules | grep -v __pycache__ | grep -v venv); do
    # Count consecutive comment lines that look like code (contain = or ( or { or ;)
    awk '
    /^[[:space:]]*(\/\/|#).*[=({;]/ { count++; start=NR-count+1; next }
    { if (count >= 3) print "  COMMENTED_CODE: " FILENAME " lines " start "-" NR-1 " (" count " lines)"; count=0 }
    END { if (count >= 3) print "  COMMENTED_CODE: " FILENAME " lines " start "-" NR " (" count " lines)" }
    ' "$f" 2>/dev/null
done

echo ""

# --- Console/debug statements ---
echo "## Debug statements in non-test files"
echo ""

grep -rn "console\.log\|console\.debug\|console\.warn\|print(\|debugger\|binding\.pry\|pdb\.set_trace\|breakpoint()" \
    --include="*.js" --include="*.ts" --include="*.tsx" --include="*.jsx" --include="*.py" --include="*.rb" \
    "$DIR" 2>/dev/null | grep -v node_modules | grep -v __pycache__ | grep -v venv | grep -v test | grep -v spec | grep -v __test__ | \
    while read -r line; do
        echo "  DEBUG_STMT: $line"
    done

echo ""
echo "=== Scan complete ==="