Initial commit
This commit is contained in:
139
commands/refactor/.scripts/analyze-complexity.sh
Executable file
139
commands/refactor/.scripts/analyze-complexity.sh
Executable 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
|
||||
128
commands/refactor/.scripts/detect-duplication.sh
Executable file
128
commands/refactor/.scripts/detect-duplication.sh
Executable 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
|
||||
174
commands/refactor/.scripts/verify-tests.sh
Executable file
174
commands/refactor/.scripts/verify-tests.sh
Executable 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
|
||||
Reference in New Issue
Block a user