mantimon-tcg/.claude/skills/frontend-code-audit/patterns/error-handling.yaml
Cal Corum b9b803da66 Scaffold Vue 3 + TypeScript frontend (Phase F0)
Vue 3 with Composition API, Pinia, Vue Router, Tailwind v4:
- Vite build with @/ path aliases and backend proxy
- TypeScript strict mode with proper type imports
- Pinia stores (auth, game) with setup syntax and persistence
- Vue Router with auth guards and lazy-loaded routes
- Tailwind v4 with custom theme (Pokemon types, dark UI)
- Vitest configured for component testing
- ESLint v9 flat config with Vue/TypeScript support

Pages: Home, Login, Register, Campaign, Collection, DeckBuilder, Match
Components: AppHeader with auth-aware navigation
Types: Card, GameState, Player, Deck, Campaign types

Also adds frontend-code-audit skill with patterns for:
- Error handling (unhandled promises, empty catches)
- Security (XSS, token storage, input validation)
- Architecture (Composition API, Pinia patterns, Phaser rules)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 09:23:53 -06:00

104 lines
3.8 KiB
YAML

# Frontend Error Handling Anti-Patterns
# Patterns that hide errors or fail to provide user feedback
name: Error Handling
description: |
Detects patterns where errors are silently swallowed, promises unhandled,
or users left without feedback when operations fail. These patterns lead
to confusing UX and hard-to-debug issues.
patterns:
- id: unhandled-promise
description: Async function called without await or .catch()
grep_pattern: '^\s+\w+\([^)]*\)\s*$'
file_glob: '*.{vue,ts}'
context_lines: 3
verdict_hints:
ISSUE_IF: "Async function (fetch, API call) with no error handling"
OK_IF: "Sync function; or fire-and-forget with documented reason"
- id: empty-catch-block
description: Catch block that does nothing with the error
grep_pattern: 'catch\s*\([^)]*\)\s*\{\s*\}'
file_glob: '*.{vue,ts}'
context_lines: 3
verdict_hints:
ISSUE_IF: "Error completely swallowed - user gets no feedback"
OK_IF: "Never OK - at minimum log or set error state"
- id: catch-only-console
description: Catch block that only logs to console
grep_pattern: 'catch.*\{[\s\n]*console\.(log|error|warn)'
multiline: true
file_glob: '*.{vue,ts}'
context_lines: 5
verdict_hints:
ISSUE_IF: "Error logged but UI shows success/no feedback to user"
OK_IF: "Also sets error state or shows toast notification"
- id: fetch-no-error-check
description: Fetch without checking response.ok
grep_pattern: 'fetch\([^)]+\)[\s\S]*?\.json\(\)'
multiline: true
file_glob: '*.{vue,ts}'
context_lines: 7
verdict_hints:
ISSUE_IF: "Response not checked for errors before parsing JSON"
OK_IF: "Uses wrapper that handles errors; or response.ok checked"
- id: missing-loading-state
description: Async operation without loading indicator
grep_pattern: 'async.*\{[\s\S]*?await.*fetch'
multiline: true
file_glob: '*.vue'
context_lines: 10
verdict_hints:
ISSUE_IF: "No isLoading ref set before/after async operation"
OK_IF: "Loading state managed by composable; or instant operation"
- id: missing-error-state
description: API call without error state handling
grep_pattern: 'await.*(fetch|api|axios)'
file_glob: '*.vue'
context_lines: 8
verdict_hints:
ISSUE_IF: "No error ref or error handling visible in component"
OK_IF: "Error handling in composable; or uses error boundary"
- id: silent-store-action
description: Store action that catches but doesn't surface errors
grep_pattern: 'catch.*\{[\s\S]*?return (false|null|undefined|\[\]|\{\})'
multiline: true
file_glob: 'stores/*.ts'
context_lines: 6
verdict_hints:
ISSUE_IF: "Store swallows error, returns falsy - caller can't show error"
OK_IF: "Also sets store.error state that UI can display"
- id: onmounted-no-error-handling
description: onMounted with async call but no error handling
grep_pattern: 'onMounted\(\s*async'
file_glob: '*.vue'
context_lines: 10
verdict_hints:
ISSUE_IF: "Async onMounted without try/catch - errors crash silently"
OK_IF: "Has try/catch with error state; or uses error boundary"
- id: watch-async-no-catch
description: Watch callback with async but no error handling
grep_pattern: 'watch\([^)]+,\s*async'
file_glob: '*.vue'
context_lines: 8
verdict_hints:
ISSUE_IF: "Async watch without error handling"
OK_IF: "Has try/catch; or errors handled by called function"
- id: socket-no-error-handler
description: Socket.io without error event handler
grep_pattern: 'socket\.(on|emit)\('
file_glob: '*.{vue,ts}'
context_lines: 10
verdict_hints:
ISSUE_IF: "Socket used without socket.on('error') or socket.on('connect_error')"
OK_IF: "Error handlers registered elsewhere (socket setup file)"