
Tech Debt Analyzer
- 115 installs
- 86 repo stars
- Updated July 17, 2026
- travisjneuman/.claude
Helps with ai & agent building tasks during AI-assisted development.
About
tech-debt-analyzer is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- tech-debt-analyzer
- AI & Agent Building
- AI-coding skill
Tech Debt Analyzer by the numbers
- 115 all-time installs (skills.sh)
- +1 installs in the week ending Jul 27, 2026 (Skillselion tracking)
- Ranked #3,917 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 3, 2026 (Skillselion catalog sync)
npx skills add https://github.com/travisjneuman/.claude --skill tech-debt-analyzerAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 115 |
|---|---|
| repo stars | ★ 86 |
| Last updated | July 17, 2026 |
| Repository | travisjneuman/.claude ↗ |
What it does
Helps with ai & agent building tasks during AI-assisted development.
Files
Technical Debt Analyzer
Systematically identify, analyze, and document technical debt.
When to Use
Use for:
- Analyzing code quality issues
- Creating technical debt registers
- Assessing code maintainability
- Identifying dependency problems
- Documenting security vulnerabilities
- Planning refactoring efforts
Don't use when:
- Writing new code → use
generic-feature-developer - Code review → use
generic-code-reviewer - Writing tests → use
test-specialist
Quick Analysis Commands
# Find large files (>500 lines)
find src -name "*.ts" -exec wc -l {} + | awk '$1 > 500' | sort -rn
# Find TODO/FIXME markers
grep -rn "TODO\|FIXME\|HACK\|XXX" src/
# Check for console.log in production code
grep -rn "console.log" src/ --include="*.ts" --include="*.tsx"
# Find TypeScript 'any' usage
grep -rn ": any" src/ --include="*.ts" --include="*.tsx"
# Check outdated dependencies
npm outdated
# Security vulnerabilities
npm audit
# Unused exports (requires ts-unused-exports)
npx ts-unused-exports tsconfig.jsonDebt Categories
| Category | Examples |
|---|---|
| Code Quality | Large files, complex functions, TODO/FIXME markers |
| Architectural | Tight coupling, missing abstractions, circular deps |
| Test | Missing coverage, fragile tests, slow execution |
| Documentation | Missing README, outdated docs, no ADRs |
| Dependency | Outdated packages, security vulnerabilities |
| Performance | N+1 queries, memory leaks, large bundles |
| Security | Missing validation, exposed secrets, XSS/SQL injection |
Analysis Workflow
1. Automated Detection
Code Smells to Check:
- Large files (>500 lines)
- Complex functions (cyclomatic complexity >10)
- Debt markers (TODO, FIXME, HACK, XXX)
- Console statements in production code
anytypes in TypeScript- Long parameter lists (>5 params)
- Deep nesting (>4 levels)
Dependency Issues:
- Deprecated packages
- Duplicate functionality
- Loose version constraints
- Known vulnerabilities
2. Severity Assessment
| Severity | Criteria | Action |
|---|---|---|
| Critical | Security vulns, data loss risk | Immediate fix |
| High | Performance problems, blocking issues | Current sprint |
| Medium | Code quality, missing docs | This quarter |
| Low | Minor smells, optimizations | When convenient |
3. Priority Matrix
| Impact / Effort | Low | Medium | High |
|---|---|---|---|
| High Impact | Do First | Do Second | Plan & Do |
| Medium Impact | Do Second | Plan & Do | Consider |
| Low Impact | Quick Win | Consider | Avoid |
Debt Register Format
## DEBT-001: Description
**Category:** Code Quality | **Severity:** High
**Location:** src/services/UserService.ts
**Description:** Brief description of the issue
**Impact:**
- Business: How it affects delivery
- Technical: Why it's problematic
- Risk: What could go wrong
**Proposed Solution:** What to do about it
**Effort:** Days/hours estimate
**Target:** Sprint/quarterPrevention Strategies
Automated Guards
{
"rules": {
"complexity": ["error", 10],
"max-lines-per-function": ["error", 50],
"max-params": ["error", 5],
"max-depth": ["error", 4]
}
}Maintenance Schedule
| Frequency | Tasks |
|---|---|
| Weekly | Review TODO/FIXME, update register |
| Monthly | Dependency updates, debt review |
| Quarterly | Full analysis, architecture review |
Self-Critique Checklist
After completing debt analysis:
- [ ] All automated checks run
- [ ] Manual review of critical paths done
- [ ] Severity assessments justified
- [ ] Proposed solutions are actionable
- [ ] Priority matrix applied consistently
- [ ] Register entries are complete
See Also
- Code Review Standards - Quality checks
- Project
CLAUDE.md- Workflow rules
ADR-XXX: [Short Title of Decision]
Status: [Proposed / Accepted / Deprecated / Superseded]
Date: [YYYY-MM-DD]
Deciders: [List of people involved in the decision]
Technical Story: [Description, ticket/issue URL]
---
Context and Problem Statement
[Describe the context and problem statement, e.g., in free form using two to three sentences. You may want to articulate the problem in form of a question.]
Key Constraints:
- [List any constraints that limit the solution space]
Key Requirements:
- [List must-have requirements]
---
Decision Drivers
[List the factors that influenced the decision, e.g.:]
- [driver 1, e.g., performance requirement]
- [driver 2, e.g., team expertise]
- [driver 3, e.g., cost constraints]
- [etc.]
---
Considered Options
Option 1: [Name]
Description: [Brief description of this option]
Pros:
- [good, because...]
- [good, because...]
Cons:
- [bad, because...]
- [bad, because...]
Effort: [Estimated effort]
---
Option 2: [Name]
Description: [Brief description of this option]
Pros:
- [good, because...]
- [good, because...]
Cons:
- [bad, because...]
- [bad, because...]
Effort: [Estimated effort]
---
Option 3: [Name]
[Repeat structure for each option considered]
---
Decision Outcome
Chosen option: "[Option X: Name]"
Rationale: [Explain why this option was chosen. What makes it the best choice given the context and decision drivers?]
---
Consequences
Positive Consequences
- [e.g., improvement of quality attribute satisfaction, follow-up decisions required, ...]
- [...]
Negative Consequences
- [e.g., compromising quality attribute, follow-up decisions required, ...]
- [...]
Technical Debt
[Any technical debt being incurred as a result of this decision? How will it be tracked?]
---
Implementation
Action Items:
- [ ] [Implementation task 1]
- [ ] [Implementation task 2]
- [ ] [etc.]
Timeline: [Expected implementation timeline]
Rollback Plan: [How to revert this decision if needed]
---
Validation
Success Metrics: [How will we measure if this decision was correct?]
Review Date: [When should we review this decision?]
---
References
- [Link to supporting documents]
- [Link to related ADRs]
- [Link to research/benchmarks]
---
Notes
[Any additional notes, context, or discussion points]
Technical Debt Register
Project: [Project Name] Last Updated: [Date] Maintained By: [Team/Person]
Summary
- Total Debt Items: 0
- Critical: 0
- High: 0
- Medium: 0
- Low: 0
- Estimated Total Effort: 0 days
---
Active Debt Items
DEBT-001: [Brief Description]
Category: [Code Quality / Architecture / Test / Documentation / Dependency / Performance / Security / Infrastructure / Design]
Severity: [Critical / High / Medium / Low]
Created: [YYYY-MM-DD]
Location:
- File(s):
path/to/file.ts - Component/Module: [Name]
Description: [Detailed description of the technical debt issue]
Impact:
- Business Impact: [How does this affect users, features, or business goals?]
- Technical Impact: [How does this affect code quality, maintainability, or performance?]
- Risk: [What could go wrong if left unaddressed?]
Root Cause: [Why was this shortcut taken? Deadline pressure, lack of knowledge, evolving requirements, etc.]
Proposed Solution: [How should this be addressed? What's the ideal fix?]
Effort Estimate: [X hours/days]
Priority Justification: [Why this severity level? Why fix this now vs later?]
Dependencies:
- Blocks: [List items this blocks]
- Blocked By: [List items blocking this]
- Related: [List related debt items]
Status: [Open / In Progress / Resolved / Won't Fix]
Assignee: [Name or Unassigned]
Target Resolution: [YYYY-MM-DD or Sprint/Quarter]
Notes:
- [Any additional context, discussion, or updates]
---
DEBT-002: [Brief Description]
[Repeat structure above for each debt item]
---
Resolved Debt Items
DEBT-XXX: [Brief Description]
Resolved Date: [YYYY-MM-DD] Resolution: [How it was fixed] Effort Spent: [Actual time taken] Lessons Learned: [What we learned from this]
---
Won't Fix Items
DEBT-XXX: [Brief Description]
Decision Date: [YYYY-MM-DD] Reason: [Why we decided not to fix this] Decision Maker: [Name/Team]
---
Debt Trends
By Category
- Code Quality: X items
- Architecture: X items
- Test: X items
- Documentation: X items
- Dependency: X items
- Performance: X items
- Security: X items
- Infrastructure: X items
- Design: X items
By Severity
- Critical: X items
- High: X items
- Medium: X items
- Low: X items
Aging
- < 1 month: X items
- 1-3 months: X items
- 3-6 months: X items
- 6-12 months: X items
- > 1 year: X items
---
Review Schedule
- Weekly: Triage new items, update status
- Monthly: Review high priority items, plan fixes
- Quarterly: Full debt review, trend analysis
---
Guidelines
When to Add Items
Add technical debt items when:
- Taking a shortcut to meet a deadline
- Discovering code smells during development
- Identifying architectural improvements
- Finding missing tests or documentation
- Detecting performance issues
- Discovering security concerns
How to Prioritize
Use this framework:
1. Critical: Security issues, production blockers, data loss risks 2. High: Blocks features, significant performance issues, high-churn areas 3. Medium: Quality issues, missing tests, outdated dependencies 4. Low: Minor improvements, optimizations, nice-to-haves
When to Fix
- Critical: Immediately
- High: Within current/next sprint
- Medium: Within quarter
- Low: When convenient or during refactoring
How to Prevent
- Code review checklist
- Automated linting and testing
- Regular dependency updates
- Documentation requirements
- Architecture reviews
export default async function tech_debt_analyzer(input) {
console.log("🧠 Running skill: tech-debt-analyzer");
// TODO: implement actual logic for this skill
return {
message: "Skill 'tech-debt-analyzer' executed successfully!",
input,
};
}
{
"name": "@ai-labs-claude-skills/tech-debt-analyzer",
"version": "1.0.0",
"description": "Claude AI skill: tech-debt-analyzer",
"main": "index.js",
"files": [
"."
],
"license": "MIT",
"author": "AI Labs"
}
Technical Debt Categories and Assessment
Overview
Technical debt represents shortcuts, workarounds, or suboptimal solutions that reduce long-term code quality and maintainability. This reference provides a comprehensive framework for identifying, categorizing, and assessing technical debt.
Debt Categories
1. Code Quality Debt
Code that works but is difficult to understand, maintain, or extend.
Indicators
Code Smells:
- Large files (>500 lines)
- Long functions (>50 lines)
- High cyclomatic complexity (>10)
- Deep nesting (>4 levels)
- Long parameter lists (>5 parameters)
- Duplicate code
- Magic numbers
- Unclear naming
Examples:
// Bad: Complex function with multiple responsibilities
function processUserData(data: any) {
if (data && data.user) {
const user = data.user;
if (user.age > 18 && user.status === "active") {
if (user.permissions) {
for (let perm of user.permissions) {
if (perm.type === "admin") {
// Deep nesting, unclear logic
if (perm.scope === "full") {
return { access: "granted", level: "admin" };
}
}
}
}
}
}
return { access: "denied" };
}Impact:
- High maintenance cost
- Difficult to understand and modify
- Error-prone
- Slows down development
Priority: Medium to High (depending on frequency of changes)
---
2. Architectural Debt
Structural issues in how code is organized and components interact.
Indicators
Tight Coupling:
- Components directly depend on implementation details
- Difficult to test in isolation
- Changes cascade across modules
Poor Separation of Concerns:
- Business logic mixed with UI code
- Data access mixed with business logic
- Multiple responsibilities in single module
Missing Abstractions:
- No clear interfaces or contracts
- Direct dependencies on concrete implementations
- Difficulty swapping implementations
Examples:
// Bad: Component tightly coupled to API implementation
function UserProfile() {
const [user, setUser] = useState(null);
useEffect(() => {
// Direct API call in component
fetch('https://api.example.com/users/123')
.then(res => res.json())
.then(data => setUser(data));
}, []);
// UI logic mixed with data transformation
const displayName = user ?
`${user.firstName} ${user.lastName}`.toUpperCase() : '';
return <div>{displayName}</div>;
}Impact:
- Difficult to modify or extend
- Hard to test
- Rigid architecture
- Prevents reuse
Priority: High (affects long-term maintainability)
---
3. Test Debt
Insufficient or inadequate test coverage.
Indicators
- Missing tests for critical functionality
- Low code coverage (<80%)
- No integration or E2E tests
- Fragile tests that break frequently
- Tests coupled to implementation details
- Slow test suite
Test Coverage Gaps:
- Untested edge cases
- Missing error handling tests
- No security tests
- No performance tests
Examples:
// Bad: Test coupled to implementation
test("UserService", () => {
const service = new UserService();
// Testing internal implementation details
expect(service.internalCache).toBeDefined();
expect(service.apiClient.baseUrl).toBe("https://api.example.com");
});
// Missing: Actual behavior tests
// - Does it fetch users correctly?
// - Does it handle errors?
// - Does it cache properly?Impact:
- Fear of refactoring
- Bugs slip into production
- Regression issues
- Slow development velocity
Priority: High for critical paths, Medium for others
---
4. Documentation Debt
Missing or outdated documentation.
Indicators
- No README or setup instructions
- Missing API documentation
- Outdated architecture diagrams
- No inline comments for complex logic
- Missing decision records (ADRs)
- No changelog
Examples:
// Bad: Complex logic with no explanation
function calculatePrice(items, user, promo) {
return (
items.reduce(
(acc, item) =>
acc +
item.price *
(1 -
(user.tier === "gold" ? 0.15 : user.tier === "silver" ? 0.1 : 0)) *
(promo?.code === "SAVE20" ? 0.8 : 1),
0,
) * (user.country === "US" ? 1.07 : 1)
);
}
// Good: Documented logic
/**
* Calculate final price with tier discounts and tax
*
* Applies:
* - Tier discount (Gold: 15%, Silver: 10%, Bronze: 0%)
* - Promo code discount (SAVE20: 20% off)
* - Sales tax (US: 7%, Other: 0%)
*/
function calculatePrice(items, user, promo) {
// Implementation with clear structure
}Impact:
- Onboarding takes longer
- Knowledge loss when developers leave
- Duplicate work
- Poor decision making
Priority: Medium (varies by project)
---
5. Dependency Debt
Issues with third-party libraries and packages.
Indicators
- Outdated dependencies
- Deprecated packages
- Security vulnerabilities
- Unused dependencies
- Version conflicts
- Duplicate functionality
Examples:
{
"dependencies": {
"moment": "^2.24.0", // Deprecated, use date-fns or dayjs
"request": "^2.88.0", // Deprecated, use axios or node-fetch
"tslint": "^6.1.0", // Deprecated, use ESLint
"lodash": "^4.17.21", // AND
"underscore": "^1.13.1" // Duplicate functionality
}
}Impact:
- Security vulnerabilities
- Missing features and bug fixes
- Larger bundle sizes
- Maintenance burden
Priority: High for security issues, Medium for others
---
6. Performance Debt
Code that works but performs poorly.
Indicators
- N+1 query problems
- Missing database indexes
- Inefficient algorithms
- Memory leaks
- Large bundle sizes
- Slow API responses
- Unnecessary re-renders
Examples:
// Bad: N+1 query problem
async function getUsersWithPosts() {
const users = await db.users.findAll();
// Separate query for each user!
for (const user of users) {
user.posts = await db.posts.findByUserId(user.id);
}
return users;
}
// Good: Single query with join
async function getUsersWithPosts() {
return db.users.findAll({
include: [{ model: db.posts }],
});
}Impact:
- Poor user experience
- Higher infrastructure costs
- Scalability issues
- Customer churn
Priority: High for user-facing features, Medium for internal tools
---
7. Security Debt
Security vulnerabilities and weaknesses.
Indicators
- Missing input validation
- No authentication/authorization
- Exposed secrets in code
- SQL injection vulnerabilities
- XSS vulnerabilities
- CSRF vulnerabilities
- Insecure dependencies
Examples:
// Bad: SQL injection vulnerability
function getUser(userId: string) {
const query = `SELECT * FROM users WHERE id = ${userId}`;
return db.query(query);
}
// Bad: XSS vulnerability
function displayComment(comment: string) {
document.getElementById("comment").innerHTML = comment;
}
// Bad: Exposed secrets
const API_KEY = "sk_live_abc123xyz789";Impact:
- Data breaches
- Legal liability
- Reputation damage
- Financial loss
Priority: Critical (immediate fix required)
---
8. Infrastructure/DevOps Debt
Issues with deployment, CI/CD, and infrastructure.
Indicators
- Manual deployment process
- No CI/CD pipeline
- Missing environment configs
- No monitoring or logging
- No backup strategy
- Hardcoded configuration
- Missing disaster recovery
Examples:
// Bad: Hardcoded environment-specific values
const config = {
apiUrl: "https://prod-api.example.com",
dbHost: "10.0.1.52",
cacheEnabled: true,
};
// Good: Environment-based configuration
const config = {
apiUrl: process.env.API_URL,
dbHost: process.env.DB_HOST,
cacheEnabled: process.env.CACHE_ENABLED === "true",
};Impact:
- Deployment errors
- Downtime
- Difficult rollbacks
- Slow incident response
Priority: High (reduces operational risk)
---
9. Design Debt
UI/UX issues and inconsistencies.
Indicators
- Inconsistent styling
- No design system
- Accessibility issues
- Poor responsive design
- Inconsistent user flows
- Duplicate components
Examples:
// Bad: Inconsistent button styling across app
<button style={{background: 'blue', padding: '10px'}}>Submit</button>
<button className="btn-primary">Submit</button>
<Button color="primary" size="lg">Submit</Button>
// Good: Consistent design system
<Button variant="primary">Submit</Button>Impact:
- Poor user experience
- Brand inconsistency
- Accessibility compliance issues
- Higher development cost
Priority: Medium (varies by product)
---
Assessment Framework
Severity Levels
Critical:
- Security vulnerabilities
- Production-breaking issues
- Data loss risks
- Immediate action required
High:
- Significant performance issues
- Architectural problems blocking features
- High-risk areas with no tests
- Action required within sprint
Medium:
- Code quality issues
- Missing documentation
- Outdated dependencies (non-security)
- Address in next few sprints
Low:
- Minor code smells
- Optimization opportunities
- Nice-to-have improvements
- Address when convenient
Impact Assessment
Business Impact:
- Does it affect user experience?
- Does it block new features?
- Does it increase costs?
- Does it create risk?
Technical Impact:
- How difficult to fix?
- How widespread is the issue?
- How frequently is code changed?
- What's the maintenance burden?
Urgency:
- Is it getting worse over time?
- Will it be harder to fix later?
- Is there a deadline or trigger event?
Prioritization Matrix
| Impact / Effort | Low Effort | Medium Effort | High Effort |
|---|---|---|---|
| High Impact | Do First | Do Second | Plan & Do |
| Medium Impact | Do Second | Plan & Do | Consider |
| Low Impact | Quick Win | Consider | Avoid |
---
Measurement Metrics
Code Quality Metrics
- Lines of Code (LOC): Track file/function sizes
- Cyclomatic Complexity: Measure code complexity
- Code Duplication: Percentage of duplicated code
- Test Coverage: Percentage of code covered by tests
- Code Churn: Frequency of changes to files
Dependency Metrics
- Outdated Dependencies: Count of packages behind latest
- Vulnerable Dependencies: Count with known CVEs
- Dependency Age: Time since last update
- Bundle Size: Total size of dependencies
Development Metrics
- Build Time: Time to build project
- Test Execution Time: Time to run test suite
- Deployment Frequency: How often code is deployed
- Lead Time: Time from commit to production
- MTTR: Mean time to recovery from incidents
---
Documentation Standards
Required Documentation
1. README.md
- Project overview
- Setup instructions
- Development workflow
- Testing approach
2. Architecture Docs
- System architecture diagram
- Data flow diagrams
- Technology stack
- Key design decisions
3. API Documentation
- Endpoint descriptions
- Request/response formats
- Authentication
- Error codes
4. Code Comments
- Complex algorithms
- Non-obvious business logic
- Workarounds and their reasons
- TODOs with context
5. ADRs (Architecture Decision Records)
- Context for major decisions
- Alternatives considered
- Rationale for choice
- Consequences
---
Prevention Strategies
Code Review Checklist
- [ ] No code smells introduced
- [ ] Tests added/updated
- [ ] Documentation updated
- [ ] No security vulnerabilities
- [ ] Performance considered
- [ ] Accessibility addressed
- [ ] No new dependencies without justification
Automated Prevention
- Linting: ESLint, TypeScript strict mode
- Formatting: Prettier, consistent style
- Testing: Required minimum coverage
- Security: Automated vulnerability scanning
- Performance: Bundle size limits, lighthouse CI
- Dependencies: Automated update PRs (Dependabot)
Regular Maintenance
- Weekly: Review TODO/FIXME comments
- Monthly: Dependency updates
- Quarterly: Architecture review
- Annually: Major refactoring initiatives
#!/usr/bin/env python3
"""
Analyze project dependencies for technical debt indicators.
This script examines package.json to identify:
- Outdated dependencies
- Unused dependencies
- Security vulnerabilities (if audit data available)
- Dependency size and complexity
Usage:
python analyze_dependencies.py [package.json-path]
"""
import json
import sys
from pathlib import Path
from datetime import datetime
from typing import Dict, List
class DependencyAnalyzer:
def __init__(self, package_json_path: str):
self.package_json_path = Path(package_json_path)
self.issues = {
'outdated': [],
'unused': [],
'duplicate_functionality': [],
'warnings': []
}
def analyze(self):
"""Analyze package.json for dependency issues."""
if not self.package_json_path.exists():
print(f"Error: {self.package_json_path} not found")
return None
try:
with open(self.package_json_path, 'r') as f:
package_data = json.load(f)
dependencies = package_data.get('dependencies', {})
dev_dependencies = package_data.get('devDependencies', {})
# Analyze version constraints
self._check_version_constraints(dependencies, 'dependencies')
self._check_version_constraints(dev_dependencies, 'devDependencies')
# Check for common duplications
self._check_duplicate_functionality(dependencies, dev_dependencies)
# Check for deprecated packages
self._check_deprecated_packages(dependencies, dev_dependencies)
return {
'package_name': package_data.get('name', 'unknown'),
'total_dependencies': len(dependencies),
'total_dev_dependencies': len(dev_dependencies),
'issues': self.issues,
'summary': self._generate_summary()
}
except json.JSONDecodeError as e:
print(f"Error parsing package.json: {e}")
return None
def _check_version_constraints(self, deps: Dict[str, str], dep_type: str):
"""Check for overly loose or strict version constraints."""
for name, version in deps.items():
# Check for wildcards or very loose constraints
if version in ['*', 'latest', '']:
self.issues['warnings'].append({
'package': name,
'type': dep_type,
'version': version,
'severity': 'high',
'message': f'Using unsafe version constraint "{version}" - can cause unexpected breaking changes'
})
# Check for missing caret or tilde
if version and version[0].isdigit():
self.issues['warnings'].append({
'package': name,
'type': dep_type,
'version': version,
'severity': 'low',
'message': f'Using exact version "{version}" - consider using ^ or ~ for flexibility'
})
def _check_duplicate_functionality(self, deps: Dict, dev_deps: Dict):
"""Check for packages that provide duplicate functionality."""
all_deps = {**deps, **dev_deps}
# Common duplications
duplication_groups = [
{
'packages': ['moment', 'dayjs', 'date-fns', 'luxon'],
'functionality': 'Date/Time manipulation'
},
{
'packages': ['lodash', 'underscore', 'ramda'],
'functionality': 'Utility functions'
},
{
'packages': ['axios', 'node-fetch', 'got', 'request'],
'functionality': 'HTTP client'
},
{
'packages': ['webpack', 'rollup', 'parcel', 'vite'],
'functionality': 'Module bundler'
},
{
'packages': ['jest', 'mocha', 'jasmine', 'vitest'],
'functionality': 'Test framework'
},
{
'packages': ['eslint', 'tslint'],
'functionality': 'Linting'
},
]
for group in duplication_groups:
found = [pkg for pkg in group['packages'] if pkg in all_deps]
if len(found) > 1:
self.issues['duplicate_functionality'].append({
'packages': found,
'functionality': group['functionality'],
'severity': 'medium',
'message': f'Multiple packages for {group["functionality"]}: {", ".join(found)}'
})
def _check_deprecated_packages(self, deps: Dict, dev_deps: Dict):
"""Check for known deprecated packages."""
deprecated = {
'request': 'Deprecated - use axios, node-fetch, or got instead',
'tslint': 'Deprecated - migrate to ESLint with @typescript-eslint',
'node-sass': 'Deprecated - use dart-sass (sass) instead',
'gulp': 'Consider modern alternatives like npm scripts or vite',
'bower': 'Deprecated - use npm or yarn',
'istanbul': 'Deprecated - use nyc instead',
'@types/node-sass': 'node-sass is deprecated',
}
all_deps = {**deps, **dev_deps}
for pkg, message in deprecated.items():
if pkg in all_deps:
dep_type = 'dependencies' if pkg in deps else 'devDependencies'
self.issues['outdated'].append({
'package': pkg,
'type': dep_type,
'version': all_deps[pkg],
'severity': 'high',
'message': message
})
def _generate_summary(self) -> Dict:
"""Generate summary statistics."""
total_issues = sum(len(issues) for issues in self.issues.values())
severity_count = {'high': 0, 'medium': 0, 'low': 0}
for category in self.issues.values():
for issue in category:
if 'severity' in issue:
severity_count[issue['severity']] += 1
return {
'total_issues': total_issues,
'by_severity': severity_count,
'by_category': {k: len(v) for k, v in self.issues.items()}
}
def format_report(analysis: Dict) -> str:
"""Format analysis results as markdown."""
if not analysis:
return "No analysis available"
report = ["# Dependency Analysis Report\n"]
report.append(f"**Package:** {analysis['package_name']}")
report.append(f"**Dependencies:** {analysis['total_dependencies']}")
report.append(f"**Dev Dependencies:** {analysis['total_dev_dependencies']}")
report.append(f"**Total Issues:** {analysis['summary']['total_issues']}\n")
report.append("## Summary\n")
for severity, count in analysis['summary']['by_severity'].items():
if count > 0:
report.append(f"- **{severity.upper()}:** {count}")
report.append("\n")
# Issues by category
category_names = {
'outdated': 'Deprecated/Outdated Packages',
'duplicate_functionality': 'Duplicate Functionality',
'warnings': 'Version Constraint Warnings',
'unused': 'Potentially Unused Dependencies'
}
for category, name in category_names.items():
issues = analysis['issues'].get(category, [])
if issues:
report.append(f"## {name} ({len(issues)})\n")
for issue in issues:
report.append(f"### {issue.get('package', 'Unknown')} ")
report.append(f"[{issue.get('severity', 'info').upper()}]\n")
report.append(f"{issue['message']}\n")
if 'version' in issue:
report.append(f"- Current version: `{issue['version']}`\n")
if 'packages' in issue:
report.append(f"- Affected packages: {', '.join(issue['packages'])}\n")
report.append("\n")
# Recommendations
report.append("## Recommendations\n")
if analysis['summary']['total_issues'] > 0:
report.append("1. Update deprecated packages to modern alternatives\n")
report.append("2. Consolidate duplicate functionality to reduce bundle size\n")
report.append("3. Run `npm audit` or `yarn audit` to check for security vulnerabilities\n")
report.append("4. Consider running `npm outdated` to check for available updates\n")
report.append("5. Use `depcheck` or similar tools to find unused dependencies\n")
else:
report.append("✅ No major dependency issues detected!\n")
return ''.join(report)
def main():
package_json_path = sys.argv[1] if len(sys.argv) > 1 else 'package.json'
analyzer = DependencyAnalyzer(package_json_path)
analysis = analyzer.analyze()
if analysis:
report = format_report(analysis)
print(report)
else:
sys.exit(1)
if __name__ == '__main__':
main()
#!/usr/bin/env python3
"""
Detect code smells and technical debt indicators in JavaScript/TypeScript codebases.
This script analyzes source code to identify:
- Large files and functions
- High complexity code
- TODO/FIXME/HACK comments
- Duplicated code patterns
- Deprecated dependencies
- Missing documentation
Usage:
python detect_code_smells.py [src-dir] [--output json|markdown]
"""
import re
import json
import sys
from pathlib import Path
from typing import List, Dict, Tuple
from collections import defaultdict
class CodeSmellDetector:
def __init__(self, src_dir: str):
self.src_dir = Path(src_dir)
self.issues = defaultdict(list)
self.stats = {
'total_files': 0,
'total_lines': 0,
'total_issues': 0
}
def analyze(self):
"""Run all analysis checks."""
for file_path in self.src_dir.rglob('*'):
if self._should_analyze(file_path):
self.stats['total_files'] += 1
self._analyze_file(file_path)
self.stats['total_issues'] = sum(len(issues) for issues in self.issues.values())
return self.issues, self.stats
def _should_analyze(self, path: Path) -> bool:
"""Check if file should be analyzed."""
if not path.is_file():
return False
# Only analyze source files
valid_extensions = {'.ts', '.tsx', '.js', '.jsx'}
if path.suffix not in valid_extensions:
return False
# Skip test files, build artifacts, and dependencies
skip_patterns = ['node_modules', 'dist', 'build', '.test.', '.spec.', '__tests__']
return not any(pattern in str(path) for pattern in skip_patterns)
def _analyze_file(self, file_path: Path):
"""Analyze a single file for code smells."""
try:
content = file_path.read_text(encoding='utf-8')
lines = content.split('\n')
self.stats['total_lines'] += len(lines)
rel_path = file_path.relative_to(self.src_dir)
# Check file size
self._check_file_size(rel_path, lines)
# Check function complexity
self._check_function_complexity(rel_path, content)
# Check for technical debt markers
self._check_debt_markers(rel_path, lines)
# Check for console statements
self._check_console_statements(rel_path, lines)
# Check for any/unknown types
self._check_weak_types(rel_path, lines)
# Check for long parameter lists
self._check_long_parameters(rel_path, content)
# Check for deep nesting
self._check_nesting_depth(rel_path, lines)
# Check for magic numbers
self._check_magic_numbers(rel_path, lines)
except Exception as e:
self.issues['errors'].append({
'file': str(file_path.relative_to(self.src_dir)),
'message': f'Error analyzing file: {str(e)}'
})
def _check_file_size(self, file_path: Path, lines: List[str]):
"""Check for overly large files."""
line_count = len(lines)
if line_count > 500:
severity = 'high' if line_count > 1000 else 'medium'
self.issues['large_files'].append({
'file': str(file_path),
'lines': line_count,
'severity': severity,
'message': f'File has {line_count} lines (should be < 500)'
})
def _check_function_complexity(self, file_path: Path, content: str):
"""Check for complex functions."""
# Match function declarations
patterns = [
r'function\s+(\w+)\s*\([^)]*\)\s*\{',
r'const\s+(\w+)\s*=\s*\([^)]*\)\s*=>\s*\{',
r'(\w+)\s*\([^)]*\)\s*\{', # Methods
]
for pattern in patterns:
for match in re.finditer(pattern, content):
func_name = match.group(1)
start_pos = match.start()
# Find function body
func_body = self._extract_function_body(content, start_pos)
if func_body:
# Count complexity indicators
complexity = self._calculate_complexity(func_body)
lines_in_func = func_body.count('\n')
if complexity > 10 or lines_in_func > 50:
severity = 'high' if complexity > 20 or lines_in_func > 100 else 'medium'
self.issues['complex_functions'].append({
'file': str(file_path),
'function': func_name,
'complexity': complexity,
'lines': lines_in_func,
'severity': severity,
'message': f'Function "{func_name}" has complexity {complexity} and {lines_in_func} lines'
})
def _extract_function_body(self, content: str, start_pos: int) -> str:
"""Extract function body using brace matching."""
brace_count = 0
in_function = False
body_start = -1
for i in range(start_pos, len(content)):
if content[i] == '{':
if not in_function:
body_start = i
in_function = True
brace_count += 1
elif content[i] == '}':
brace_count -= 1
if brace_count == 0 and in_function:
return content[body_start:i+1]
return ''
def _calculate_complexity(self, code: str) -> int:
"""Calculate cyclomatic complexity."""
complexity = 1 # Base complexity
# Count decision points
patterns = [
r'\bif\b',
r'\belse\s+if\b',
r'\bfor\b',
r'\bwhile\b',
r'\bcase\b',
r'\bcatch\b',
r'\&\&',
r'\|\|',
r'\?', # Ternary operator
]
for pattern in patterns:
complexity += len(re.findall(pattern, code))
return complexity
def _check_debt_markers(self, file_path: Path, lines: List[str]):
"""Check for TODO, FIXME, HACK, XXX comments."""
markers = ['TODO', 'FIXME', 'HACK', 'XXX', 'BUG', 'DEPRECATED']
for line_num, line in enumerate(lines, 1):
for marker in markers:
if marker in line.upper() and ('//' in line or '/*' in line):
# Extract the comment
comment = line.strip()
severity = 'high' if marker in ['FIXME', 'BUG', 'HACK'] else 'low'
self.issues['debt_markers'].append({
'file': str(file_path),
'line': line_num,
'marker': marker,
'severity': severity,
'comment': comment,
'message': f'{marker} comment found'
})
def _check_console_statements(self, file_path: Path, lines: List[str]):
"""Check for console.log statements left in code."""
for line_num, line in enumerate(lines, 1):
if re.search(r'\bconsole\.(log|debug|info|warn|error)\(', line):
# Skip if it's commented out
if '//' in line and line.index('//') < line.index('console'):
continue
self.issues['console_statements'].append({
'file': str(file_path),
'line': line_num,
'severity': 'low',
'code': line.strip(),
'message': 'Console statement left in code'
})
def _check_weak_types(self, file_path: Path, lines: List[str]):
"""Check for 'any' or 'unknown' types in TypeScript."""
if not str(file_path).endswith(('.ts', '.tsx')):
return
for line_num, line in enumerate(lines, 1):
# Check for : any or <any>
if re.search(r':\s*any\b|<any>', line):
# Skip if it's in a comment
if '//' in line and line.index('//') < line.index('any'):
continue
self.issues['weak_typing'].append({
'file': str(file_path),
'line': line_num,
'severity': 'medium',
'code': line.strip(),
'message': 'Using "any" type reduces type safety'
})
def _check_long_parameters(self, file_path: Path, content: str):
"""Check for functions with too many parameters."""
# Match function signatures
pattern = r'(?:function\s+\w+|const\s+\w+\s*=.*?)\s*\(([^)]+)\)'
for match in re.finditer(pattern, content):
params = match.group(1)
# Count parameters (simple comma split)
param_count = len([p for p in params.split(',') if p.strip()])
if param_count > 5:
severity = 'high' if param_count > 7 else 'medium'
# Find line number
line_num = content[:match.start()].count('\n') + 1
self.issues['long_parameters'].append({
'file': str(file_path),
'line': line_num,
'parameters': param_count,
'severity': severity,
'message': f'Function has {param_count} parameters (should be < 5)'
})
def _check_nesting_depth(self, file_path: Path, lines: List[str]):
"""Check for deeply nested code."""
max_depth = 0
current_depth = 0
for line_num, line in enumerate(lines, 1):
# Simple brace counting
current_depth += line.count('{') - line.count('}')
if current_depth > max_depth:
max_depth = current_depth
if current_depth > 4:
severity = 'high' if current_depth > 6 else 'medium'
self.issues['deep_nesting'].append({
'file': str(file_path),
'line': line_num,
'depth': current_depth,
'severity': severity,
'message': f'Nesting depth of {current_depth} (should be < 4)'
})
def _check_magic_numbers(self, file_path: Path, lines: List[str]):
"""Check for magic numbers in code."""
for line_num, line in enumerate(lines, 1):
# Skip comments and strings
if '//' in line or '/*' in line or '"' in line or "'" in line:
continue
# Find numbers that aren't 0, 1, -1, 100 (common non-magic numbers)
numbers = re.findall(r'\b(\d{2,})\b', line)
for num in numbers:
if int(num) not in [0, 1, 10, 100, 1000]:
self.issues['magic_numbers'].append({
'file': str(file_path),
'line': line_num,
'number': num,
'severity': 'low',
'code': line.strip(),
'message': f'Magic number {num} should be a named constant'
})
break # One per line is enough
def format_markdown_report(issues: Dict, stats: Dict) -> str:
"""Format issues as markdown report."""
report = ["# Technical Debt Analysis Report\n"]
report.append(f"**Generated:** {__import__('datetime').datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
report.append("## Summary\n")
report.append(f"- **Files Analyzed:** {stats['total_files']}")
report.append(f"- **Total Lines:** {stats['total_lines']}")
report.append(f"- **Total Issues:** {stats['total_issues']}\n")
# Calculate severity distribution
severity_count = defaultdict(int)
for category_issues in issues.values():
for issue in category_issues:
if 'severity' in issue:
severity_count[issue['severity']] += 1
report.append("### Issues by Severity\n")
for severity in ['high', 'medium', 'low']:
count = severity_count.get(severity, 0)
report.append(f"- **{severity.upper()}:** {count}")
report.append("\n")
# Issues by category
category_names = {
'large_files': 'Large Files',
'complex_functions': 'Complex Functions',
'debt_markers': 'Technical Debt Markers',
'console_statements': 'Console Statements',
'weak_typing': 'Weak Typing',
'long_parameters': 'Long Parameter Lists',
'deep_nesting': 'Deep Nesting',
'magic_numbers': 'Magic Numbers',
'errors': 'Analysis Errors'
}
for category, name in category_names.items():
category_issues = issues.get(category, [])
if category_issues:
report.append(f"## {name} ({len(category_issues)} issues)\n")
# Group by severity
high = [i for i in category_issues if i.get('severity') == 'high']
medium = [i for i in category_issues if i.get('severity') == 'medium']
low = [i for i in category_issues if i.get('severity') == 'low']
for severity, severity_issues in [('High', high), ('Medium', medium), ('Low', low)]:
if severity_issues:
report.append(f"### {severity} Priority\n")
for issue in severity_issues[:10]: # Limit to 10 per severity
report.append(f"- **{issue['file']}**")
if 'line' in issue:
report.append(f" (line {issue['line']})")
report.append(f": {issue['message']}")
if 'code' in issue:
report.append(f"\n ```\n {issue['code']}\n ```")
report.append("\n")
if len(severity_issues) > 10:
report.append(f"\n_... and {len(severity_issues) - 10} more_\n")
report.append("\n")
return ''.join(report)
def main():
src_dir = sys.argv[1] if len(sys.argv) > 1 else 'src'
output_format = 'markdown'
if '--output' in sys.argv:
idx = sys.argv.index('--output')
if idx + 1 < len(sys.argv):
output_format = sys.argv[idx + 1]
if not Path(src_dir).exists():
print(f"Error: Source directory not found: {src_dir}")
sys.exit(1)
print(f"Analyzing codebase in: {src_dir}")
detector = CodeSmellDetector(src_dir)
issues, stats = detector.analyze()
if output_format == 'json':
result = {
'stats': stats,
'issues': dict(issues)
}
print(json.dumps(result, indent=2))
else:
report = format_markdown_report(issues, stats)
print(report)
if __name__ == '__main__':
main()