# 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)"
