Claude-skill-registry Lint Cleanup
FIX ESLint errors safely without breaking code. Prefix unused variables with `_`, fix no-case-declarations, add default props, and verify builds after each batch. Use when lint cleanup is needed for easier refactoring & faster Claude Code editing.
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/dev-lint-cleanup" ~/.claude/skills/majiayu000-claude-skill-registry-lint-cleanup && rm -rf "$T"
skills/data/dev-lint-cleanup/SKILL.mdSafe Lint Cleanup
Instructions
This skill provides safe patterns for fixing ESLint errors without breaking code.
Pre-Flight Checklist
BEFORE starting any lint cleanup:
# 1. Get baseline count npm run lint 2>&1 | tail -5 # 2. Save full output for reference npm run lint 2>&1 > /tmp/lint-output.txt # 3. Verify build works npm run build # 4. Check git status (ensure clean state) git status
Error Categories & Fixes
1. Unused Variables (@typescript-eslint/no-unused-vars
)
@typescript-eslint/no-unused-varsPattern 1: Prefix Unused Variables with _
_This is the SAFEST fix - silences the error without changing logic:
// BEFORE (error) const unusedVar = someValue // AFTER (no error) const _unusedVar = someValue
Pattern 2: Prefix Unused Function Parameters
// BEFORE const handleClick = (event: MouseEvent) => { // doesn't use event } // AFTER const handleClick = (_event: MouseEvent) => { // doesn't use event }
Pattern 3: Destructuring with Rename
// BEFORE const { unusedProp, usedProp } = options // AFTER const { unusedProp: _unusedProp, usedProp } = options
Pattern 4: Unused Type Imports
// BEFORE import { SomeType, UsedType } from '@/types' // AFTER import type { SomeType as _SomeType, UsedType } from '@/types'
Pattern 5: Remove Completely Unused Imports
// BEFORE import { ref, watch, computed } from 'vue' // watch never used // AFTER import { ref, computed } from 'vue'
2. Case Declarations (no-case-declarations
)
no-case-declarationsError:
Unexpected lexical declaration in case block
Cause: Using
const, let, or class directly in a case block without braces.
Fix: Wrap case block contents in
{} to create block scope.
// BEFORE (error) switch (type) { case 'foo': const value = computeValue() // ERROR! doSomething(value) break case 'bar': const other = computeOther() // ERROR! doOther(other) break } // AFTER (fixed) switch (type) { case 'foo': { const value = computeValue() doSomething(value) break } case 'bar': { const other = computeOther() doOther(other) break } }
Quick find pattern:
# Find files with case declarations errors npm run lint 2>&1 | grep "no-case-declarations" -B1 | grep -E "^/" | sort -u
3. Vue Default Props (vue/require-default-prop
)
vue/require-default-propError:
Prop 'X' requires default value to be set
Cause: Optional props without default values in Vue 3
<script setup>.
Fix: Use
withDefaults() to provide default values.
<!-- BEFORE (error) --> <script setup lang="ts"> interface Props { title?: string count?: number items?: string[] } const props = defineProps<Props>() </script> <!-- AFTER (fixed) --> <script setup lang="ts"> interface Props { title?: string count?: number items?: string[] } const props = withDefaults(defineProps<Props>(), { title: '', count: 0, items: () => [] // Use factory for arrays/objects }) </script>
Default value rules:
- Primitives: Use direct value (
,''
,0
,false
)null - Arrays: Use factory function
() => [] - Objects: Use factory function
() => ({})
4. Boolean Shorthand (vue/prefer-true-attribute-shorthand
)
vue/prefer-true-attribute-shorthandError:
Boolean attribute should be written in shorthand form
Cause: Using
:prop="true" instead of just prop.
<!-- BEFORE (error) --> <MyComponent :is-active="true" :show-header="true" /> <!-- AFTER (fixed) --> <MyComponent is-active show-header />
5. Empty Object Types (@typescript-eslint/no-empty-object-type
)
@typescript-eslint/no-empty-object-typeError:
The {} type is not recommended
Cause: Using
{} as a type in TypeScript (especially in .d.ts files).
Fix: Use
object or Record<string, never> instead, OR exclude .d.ts files:
// In eslint.config.js ignores: ignores: ['**/*.d.ts']
6. ESLint Config Alignment
Problem: Files excluded from
tsconfig.json but not from ESLint cause parsing errors.
Fix: Keep ESLint ignores aligned with tsconfig excludes:
// eslint.config.js { ignores: [ 'node_modules/**', 'dist/**', '**/*.d.ts', // Match tsconfig.json exclude patterns: 'src/stories/**', 'src/composables/adapters/**', 'src/sync/**', 'src/utils/emojiDetection.ts', 'src/utils/logger.ts', // etc. ] }
ESLint Config for Underscore Pattern
CRITICAL: The underscore pattern must be configured for BOTH
.ts AND .vue files:
// eslint.config.js // For TypeScript files { files: ['**/*.ts', '**/*.tsx'], rules: { '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_', varsIgnorePattern: '^_', caughtErrorsIgnorePattern: '^_' }] } } // For Vue files - MUST BE SEPARATE! { files: ['**/*.vue'], rules: { '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_', varsIgnorePattern: '^_', caughtErrorsIgnorePattern: '^_' }] } }
Verification Process
After every batch of fixes:
# 1. Run build npm run build 2>&1 | tail -10 # 2. Check new lint count npm run lint 2>&1 | tail -5 # 3. Calculate progress # (baseline - current) / baseline * 100 = % fixed
Files to Be Careful With
| File Type | Reason |
|---|---|
| Vue components with templates | Variables might be used in template |
| Store files | Exported functions might appear unused |
| Composables | Returned values might appear unused |
| Test files | May have intentional unused vars |
files | Type declarations may use special patterns |
Error Priority Order
Fix errors in this order (highest impact first):
- Parsing errors - ESLint ignores alignment with tsconfig
- no-case-declarations - Structural fixes, wrap in
{} - require-default-prop - Add
withDefaults() - no-unused-vars - Prefix with
or remove_ - prefer-true-attribute-shorthand - Simple template fixes
- no-explicit-any - Requires proper typing (lower priority)
Quick Reference Commands
# Get current lint count npm run lint 2>&1 | tail -5 # Save full output npm run lint 2>&1 > /tmp/lint-output.txt # Find files with specific error npm run lint 2>&1 | grep "ERROR_NAME" -B1 | grep -E "^/" | sort -u # Count specific error type grep "ERROR_NAME" /tmp/lint-output.txt | wc -l # Check specific file errors cat /tmp/lint-output.txt | grep -A20 "YourFile.vue$" | head -25 # Run --fix for auto-fixable errors (safe) npm run lint -- --fix # Find case declarations by file awk '/^\/home.*\.(vue|ts)$/ { file=$0 } /no-case-declarations/ { print file }' /tmp/lint-output.txt | sort -u
Common Gotchas
- Multiple Matches: Add more surrounding context to make match unique
- Variable Used in Template: Check
section before prefixing<template> - Exported but Appears Unused: Don't prefix exports - used externally
- Store/Composable Return Values: Check if values are returned for consumers
- Case Block Fallthrough: Ensure
is inside thebreak
braces{} - Factory Functions for Props: Arrays/objects need
not() => [][]
See
lint-cleanup-guide.md for complete documentation.