444 lines
13 KiB
Markdown
444 lines
13 KiB
Markdown
# Linter-Driven Development Reference (TypeScript + React)
|
|
|
|
## Overview
|
|
|
|
The linter-driven development workflow ensures code quality through automated tooling and design validation. This orchestrator manages the complete lifecycle from design to commit-ready code.
|
|
|
|
## Quality Tool Stack
|
|
|
|
### 1. TypeScript Compiler (`tsc`)
|
|
**Command**: `npm run typecheck`
|
|
**Purpose**: Type safety validation
|
|
**Can auto-fix**: No
|
|
**Failure resolution**: Manual type fixes or refactoring
|
|
|
|
### 2. ESLint
|
|
**Command**:
|
|
- Check: `npm run lintcheck`
|
|
- Fix: `npm run lint`
|
|
|
|
**Purpose**: Code quality, style, and complexity analysis
|
|
**Plugins used**:
|
|
- `eslint-plugin-sonarjs` - Complexity metrics (THE KEY PLUGIN)
|
|
- `typescript-eslint` - TypeScript-aware linting
|
|
- `eslint-plugin-react` - React best practices
|
|
- `eslint-plugin-react-hooks` - Hooks rules enforcement
|
|
- `eslint-plugin-jsx-a11y` - Accessibility rules
|
|
- `eslint-plugin-import` - Import/export management
|
|
- `eslint-plugin-unused-imports` - Remove dead code
|
|
- `eslint-plugin-simple-import-sort` - Auto-sort imports
|
|
- `eslint-plugin-promise` - Async/await best practices
|
|
- `eslint-plugin-security` - Security vulnerabilities
|
|
|
|
**Can auto-fix**: Many rules (formatting, imports, simple violations)
|
|
**Requires refactoring**: Complexity rules, design issues
|
|
|
|
### 3. Prettier
|
|
**Command**:
|
|
- Check: `npm run formatcheck`
|
|
- Fix: `npm run format`
|
|
|
|
**Purpose**: Code formatting consistency
|
|
**Can auto-fix**: Always (100% auto-fixable)
|
|
|
|
### 4. Stylelint
|
|
**Command**:
|
|
- Check: `npm run stylecheck`
|
|
- Fix: `npm run stylefix`
|
|
|
|
**Purpose**: SCSS/CSS linting
|
|
**Can auto-fix**: Most rules
|
|
|
|
## Workflow Phases in Detail
|
|
|
|
### Phase 1: Design
|
|
|
|
**Trigger**: New components, custom hooks, major architectural changes
|
|
|
|
**Actions**:
|
|
1. Invoke @component-designing skill
|
|
2. Answer design questions:
|
|
- Component composition strategy?
|
|
- State management approach?
|
|
- Custom hooks needed?
|
|
- Type definitions required?
|
|
3. Receive design plan with:
|
|
- Component structure
|
|
- Props interfaces
|
|
- Custom hooks
|
|
- Type definitions
|
|
- File organization
|
|
|
|
**Output**: Design document ready for implementation
|
|
|
|
### Phase 2: Implementation + Testing
|
|
|
|
**Testing principles** (from @testing skill):
|
|
- Write tests for public API only
|
|
- Use React Testing Library patterns
|
|
- Test user behavior, not implementation
|
|
- Use MSW for API mocking (real HTTP)
|
|
- Avoid `waitFor` with arbitrary delays
|
|
- Achieve 100% coverage on leaf components/hooks (no dependencies on other types)
|
|
- Integration tests for orchestrating components (test interactions and composition)
|
|
|
|
**Implementation approach**:
|
|
- Parallel development (test + code together)
|
|
- Focus on behavior validation
|
|
- Use real implementations over mocks
|
|
- Follow component composition patterns
|
|
- Push business logic into leaf types for better testability
|
|
|
|
### Phase 3: Linter Loop
|
|
|
|
This is the core quality gate with multiple sub-checks:
|
|
|
|
#### Step 1: Type Checking
|
|
```bash
|
|
npm run typecheck
|
|
```
|
|
**Checks**: TypeScript compilation, type safety
|
|
**Failures**: Type errors, missing types, type mismatches
|
|
**Resolution**:
|
|
- Fix types manually
|
|
- Add type assertions where needed
|
|
- Use type guards for narrowing
|
|
- Cannot proceed if failing
|
|
|
|
#### Step 2: ESLint Check
|
|
```bash
|
|
npm run lintcheck
|
|
```
|
|
**Checks**: Code quality, complexity, React rules, hooks rules, a11y
|
|
**Failures**: See "ESLint Failure Categories" below
|
|
**Resolution**:
|
|
- Auto-fix: `npm run lint`
|
|
- If auto-fix insufficient → manual fixes or invoke @refactoring
|
|
|
|
#### Step 3: Prettier Check
|
|
```bash
|
|
npm run formatcheck
|
|
```
|
|
**Checks**: Code formatting consistency
|
|
**Failures**: Inconsistent formatting
|
|
**Resolution**: Always auto-fix with `npm run format`
|
|
|
|
#### Step 4: Stylelint Check
|
|
```bash
|
|
npm run stylecheck
|
|
```
|
|
**Checks**: SCSS/CSS quality and consistency
|
|
**Failures**: Style violations, naming issues
|
|
**Resolution**: Auto-fix with `npm run stylefix`, some manual fixes
|
|
|
|
#### Loop Behavior
|
|
```
|
|
Run all checks → Any fail? → Run auto-fixes → Re-run checks
|
|
↓
|
|
Still failing?
|
|
↓
|
|
Complexity/design issues?
|
|
↓
|
|
Invoke @refactoring
|
|
↓
|
|
Re-run checks
|
|
↓
|
|
Loop until pass
|
|
```
|
|
|
|
### Phase 4: Pre-Commit Review (Advisory)
|
|
|
|
**Always invoked**, even if linter passes.
|
|
|
|
**Purpose**: Validate design principles that linters cannot enforce
|
|
|
|
**Scope**:
|
|
- **Primary**: All changed code in current commit
|
|
- **Secondary**: Broader file context (flags patterns for future refactoring)
|
|
|
|
**Categories**:
|
|
- 🔴 **Design Debt**: Will cause pain when extending code
|
|
- Primitive obsession (string IDs, unvalidated inputs)
|
|
- Prop drilling (state passed through 3+ levels)
|
|
- Tight coupling
|
|
- Missing error boundaries
|
|
- Non-self-validating types
|
|
|
|
- 🟡 **Readability Debt**: Hard to understand and work with
|
|
- Mixed abstraction levels
|
|
- Complex nested logic
|
|
- Inline styles or logic
|
|
- Poor naming
|
|
- Missing component extraction
|
|
|
|
- 🟢 **Polish Opportunities**: Minor improvements
|
|
- Missing JSDoc
|
|
- Accessibility enhancements
|
|
- Type refinements
|
|
- Better naming
|
|
|
|
**Output**: Advisory report with specific line references and fix suggestions
|
|
|
|
**User Decision Points**:
|
|
1. Commit as-is (accept debt)
|
|
2. Fix design debt (🔴) - recommended
|
|
3. Fix design + readability (🔴 + 🟡)
|
|
4. Fix all (🔴 🟡 🟢)
|
|
5. Expand scope (refactor related code)
|
|
|
|
### Phase 5: Commit Ready
|
|
|
|
**Checklist**:
|
|
- ✅ Type checking passes
|
|
- ✅ ESLint passes
|
|
- ✅ Prettier passes
|
|
- ✅ Stylelint passes
|
|
- ✅ Tests pass (100% coverage on leaf types, integration tests on orchestrating components)
|
|
- ✅ Design review complete (advisory)
|
|
|
|
**Output**:
|
|
- Commit readiness summary
|
|
- Suggested commit message
|
|
- List of modified/added files
|
|
- Coverage report
|
|
- Design review findings
|
|
- User decision prompt
|
|
|
|
## Coverage Targets
|
|
|
|
Follow @testing skill principles for coverage strategy:
|
|
|
|
- **Leaf types** (pure logic, no external dependencies): 100% unit test coverage
|
|
- **Orchestrating types** (coordinate pieces, call external systems): Integration tests
|
|
|
|
See **testing/reference.md** for:
|
|
- Detailed coverage targets explanation
|
|
- Examples of leaf vs orchestrating types
|
|
- Testing approach for each type
|
|
- Architectural benefits
|
|
|
|
## ESLint Failure Categories
|
|
|
|
### Category 1: Auto-Fixable (npm run lint)
|
|
These are fixed automatically:
|
|
- Unused imports (`unused-imports/no-unused-imports`)
|
|
- Import sorting (`simple-import-sort/imports`)
|
|
- Missing semicolons, quotes, spacing (handled by Prettier)
|
|
- Simple style violations
|
|
- Arrow function simplification (`arrow-body-style`)
|
|
|
|
**Action**: Run `npm run lint` → Re-run checks → Continue
|
|
|
|
### Category 2: Requires Manual Fix
|
|
These need developer intervention but are straightforward:
|
|
- `@typescript-eslint/no-explicit-any` - Replace any with proper types
|
|
- `no-console` - Remove or replace with proper logging
|
|
- `react/jsx-key` - Add key props to list items
|
|
- `react-hooks/exhaustive-deps` - Fix hook dependencies
|
|
- Type-related issues
|
|
|
|
**Action**: Fix issues manually → Re-run checks → Continue
|
|
|
|
### Category 3: Requires Refactoring (invoke @refactoring)
|
|
These indicate design or complexity problems:
|
|
- `sonarjs/cognitive-complexity` (max: 15)
|
|
- `sonarjs/cyclomatic-complexity` (max: 10)
|
|
- `sonarjs/expression-complexity` (max: 5)
|
|
- `sonarjs/max-lines-per-function` (max: 200)
|
|
- `sonarjs/max-lines` (max: 600)
|
|
- `sonarjs/nested-control-flow` (max: 4 levels)
|
|
- `react/no-unstable-nested-components` - Extract components
|
|
- `react/no-multi-comp` - Split into multiple files
|
|
|
|
**Action**: Invoke @refactoring skill → Apply patterns (storifying, extract hooks/functions, early returns, simplify conditionals) → Re-run checks → Continue
|
|
|
|
## Complexity Thresholds Explained
|
|
|
|
### Cognitive Complexity (max: 15)
|
|
**What it measures**: How difficult is it to understand the code?
|
|
**Increments for**: Nested structures, breaks in linear flow, recursion
|
|
**Why it matters**: High cognitive load → more bugs, harder maintenance
|
|
|
|
**How to fix**: Invoke @refactoring skill which applies **storifying** - making code read like a story at single abstraction level. See refactoring/reference.md for detailed techniques and examples.
|
|
|
|
**Example violation**:
|
|
```tsx
|
|
// Cognitive complexity: 18 (too high!)
|
|
function validateUser(user: User): ValidationResult {
|
|
if (user) { // +1
|
|
if (user.email) { // +2 (nested)
|
|
if (isValidEmail(user.email)) { // +3 (nested)
|
|
if (user.age >= 18) { // +4 (nested)
|
|
if (user.country === 'US') { // +5 (nested)
|
|
return { valid: true }
|
|
} else { // +1
|
|
return { valid: false, reason: 'Not in US' }
|
|
}
|
|
}
|
|
} else { // +1
|
|
return { valid: false, reason: 'Invalid email' }
|
|
}
|
|
}
|
|
}
|
|
return { valid: false, reason: 'Missing user' }
|
|
}
|
|
```
|
|
|
|
**How to fix**: Invoke @refactoring skill to storify with early returns (see refactoring/reference.md)
|
|
|
|
### Cyclomatic Complexity (max: 10)
|
|
**What it measures**: Number of independent paths through code
|
|
**Increments for**: if, else, case, &&, ||, while, for, catch
|
|
**Why it matters**: More paths → more test cases needed, higher bug risk
|
|
|
|
**Fix strategies**: Extract functions, use polymorphism, simplify conditionals
|
|
|
|
### Expression Complexity (max: 5)
|
|
**What it measures**: Number of operators in a single expression
|
|
**Increments for**: &&, ||, ternary operators
|
|
**Why it matters**: Hard to read, error-prone
|
|
|
|
**Example violation**:
|
|
```tsx
|
|
// Expression complexity: 6 (too high!)
|
|
const isValid = user && user.email && isValidEmail(user.email) && user.age >= 18 && user.country === 'US' && !user.banned
|
|
```
|
|
|
|
**Fix**: Extract to variables or validation function
|
|
|
|
### Storifying Pattern
|
|
|
|
When cognitive complexity is high, invoke @refactoring skill which applies storifying patterns (making code read like a story at single abstraction level).
|
|
|
|
See **refactoring/reference.md** for:
|
|
- Detailed storifying explanation with examples
|
|
- TypeScript and React examples
|
|
- When and how to apply storifying
|
|
- Step-by-step storifying process
|
|
|
|
## Integration with Other Skills
|
|
|
|
### @component-designing
|
|
**When invoked**: Phase 1, if new components/major changes needed
|
|
**Input**: Feature requirements
|
|
**Output**: Component structure, props, hooks, types
|
|
**Next step**: Proceed to Phase 2 implementation
|
|
|
|
### @testing
|
|
**When applied**: Phase 2, during implementation
|
|
**Input**: Component/hook to test
|
|
**Output**: Test files with React Testing Library
|
|
**Principles**: User-centric testing, real implementations
|
|
|
|
### @refactoring
|
|
**When invoked**: Phase 3, when linter fails on complexity
|
|
**Input**: Failing component/function + linter error
|
|
**Output**: Refactored code that passes linter
|
|
**Patterns**: Storifying, extract hooks/functions, simplify logic, early returns, single abstraction levels
|
|
|
|
### @pre-commit-review
|
|
**When invoked**: Phase 4, always (advisory)
|
|
**Input**: All changed code + file context
|
|
**Output**: Design review findings (🔴 🟡 🟢)
|
|
**Decision**: User chooses whether to apply fixes
|
|
|
|
### @documentation
|
|
**When invoked**: After commit (feature complete)
|
|
**Input**: Implemented feature
|
|
**Output**: Storybook stories, JSDoc, feature docs
|
|
**Purpose**: Documentation for humans and AI
|
|
|
|
## Command Alternatives
|
|
|
|
Different projects may use different naming conventions:
|
|
|
|
### Option 1: Separate check/fix commands
|
|
```bash
|
|
# Checks (validation only)
|
|
npm run typecheck
|
|
npm run lintcheck
|
|
npm run formatcheck
|
|
npm run stylecheck
|
|
|
|
# Fixes (auto-fix where possible)
|
|
npm run lint
|
|
npm run format
|
|
npm run stylefix
|
|
```
|
|
|
|
### Option 2: Combined commands
|
|
```bash
|
|
# Check all quality gates
|
|
npm run checkall # or npm run check
|
|
|
|
# Fix all auto-fixable issues
|
|
npm run fix
|
|
```
|
|
|
|
### Option 3: Task runner (if available)
|
|
```bash
|
|
# Using task runner (e.g., make, task)
|
|
task lint
|
|
task fix
|
|
```
|
|
|
|
**Plugin should detect** which commands are available from `package.json` scripts.
|
|
|
|
## Best Practices
|
|
|
|
### 1. Fail Fast, Fix Fast
|
|
- Run linter frequently during development
|
|
- Don't accumulate linter errors
|
|
- Fix auto-fixable issues immediately
|
|
|
|
### 2. Trust Complexity Metrics
|
|
- SonarJS complexity rules are calibrated well
|
|
- If it flags complexity → there's real complexity
|
|
- Refactor rather than disable
|
|
|
|
### 3. Respect Advisory Review
|
|
- Design debt compounds over time
|
|
- Fix 🔴 before committing when possible
|
|
- Track accepted debt in tickets
|
|
|
|
### 4. Test After Refactoring
|
|
- Complexity fixes can introduce bugs
|
|
- Re-run tests after @refactoring
|
|
- Verify behavior unchanged
|
|
|
|
### 5. Commit Granularly
|
|
- Small, focused commits
|
|
- Each commit passes all gates
|
|
- Easy to review and revert
|
|
|
|
## Troubleshooting
|
|
|
|
### "Type errors won't go away"
|
|
- TypeScript errors require manual fixes
|
|
- Consider if types are correct (not the code)
|
|
- Use type guards for narrowing
|
|
- Add type assertions as last resort
|
|
|
|
### "ESLint keeps failing after auto-fix"
|
|
- Auto-fix only handles simple rules
|
|
- Complexity rules need refactoring
|
|
- Invoke @refactoring skill
|
|
- May need architectural changes
|
|
|
|
### "Linter passes but review finds issues"
|
|
- Expected! Linters can't enforce design principles
|
|
- Review catches: primitive obsession, coupling, architecture
|
|
- User decides whether to fix
|
|
|
|
### "Too many findings in review"
|
|
- Common for legacy code
|
|
- Fix incrementally (design debt first)
|
|
- Consider broader refactor ticket
|
|
- Don't let perfect be enemy of good
|
|
|
|
## Related Files
|
|
- For design patterns: See @component-designing/reference.md
|
|
- For testing strategies: See @testing/reference.md
|
|
- For refactoring patterns: See @refactoring/reference.md
|
|
- For review principles: See @pre-commit-review/reference.md
|