All files error-handler.ts

84.37% Statements 54/64
80% Branches 40/50
100% Functions 10/10
84.37% Lines 54/64

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 1791x 1x                     1x           4x 4x   4x 1x 1x 3x 2x 2x   1x 1x     4x 4x       4x     4x 3x               7x   2x 2x                     2x 2x 2x 1x   1x         1x 1x         1x 1x         1x 1x                                             8x   8x 2x     6x         1x     5x 1x     4x 1x     3x 1x     2x 1x     1x             1x       1x               1x 1x       1x       1x       1x       1x      
import { Notice } from 'obsidian';
import {
  OllamaError,
  ErrorType,
  NetworkError,
  ApiError,
  ValidationError,
  StreamingError,
  ToolExecutionError,
  PathValidationError,
} from './types';
 
export class ErrorHandler {
  /**
   * Centralized error handling for the Ollama plugin
   * Provides consistent error messages and logging
   */
  static handleError(error: unknown, context?: string): void {
    let userMessage = 'An unexpected error occurred';
    let shouldShowError = true;
 
    if (error instanceof OllamaError) {
      userMessage = this.getUserFriendlyMessage(error);
      shouldShowError = true;
    } else if (error instanceof Error) {
      userMessage = this.getUserFriendlyMessageFromError(error);
      shouldShowError = true;
    } else {
      userMessage = 'An unexpected error occurred';
      shouldShowError = true;
    }
 
    if (shouldShowError) {
      new Notice(userMessage);
    }
 
    // Log detailed error for debugging
    console.error(
      `[OllamaPlugin${context ? ' ' + context : ''}] ${error instanceof Error ? error.message : 'Unknown error'}`
    );
    if (error instanceof Error) {
      console.error('[Stack]', error.stack);
    }
  }
 
  /**
   * Get user-friendly message from specific error types
   */
  private static getUserFriendlyMessage(error: OllamaError): string {
    switch (error.type) {
      case ErrorType.NETWORK_ERROR:
        if (error instanceof NetworkError) {
          return 'Connection error. Please check if Ollama is running.';
        }
        return 'Network error. Please check your connection to Ollama.';
 
      case ErrorType.API_ERROR:
        Iif (error instanceof ApiError) {
          return 'Ollama API error. Please check the Ollama logs for details.';
        }
        return 'API communication error. Please try again.';
 
      case ErrorType.VALIDATION_ERROR:
        if (error instanceof ValidationError) {
          const details = error.validationDetails;
          if (details?.field) {
            return `Invalid ${details.field}. ${details.message || 'Please check your input.'}`;
          }
          return 'Input validation error. Please correct your input.';
        }
        return 'Input validation error. Please correct your input.';
 
      case ErrorType.STREAMING_ERROR:
        if (error instanceof StreamingError) {
          return 'Response too long. Please try a shorter request.';
        }
        return 'Streaming error. Please try again.';
 
      case ErrorType.TOOL_EXECUTION_ERROR:
        if (error instanceof ToolExecutionError) {
          return `Tool error: ${error.toolName || 'tool'} failed to execute. Please try again.`;
        }
        return 'Tool execution error. Please try a different command.';
 
      case ErrorType.PATH_VALIDATION_ERROR:
        if (error instanceof PathValidationError) {
          return 'Invalid file path. Please use a relative path without special characters.';
        }
        return 'Path validation error. Please check your file path.';
 
      case ErrorType.UNKNOWN_ERROR:
        return 'An unexpected error occurred. Please try again.';
 
      default:
        return error.message || 'An error occurred';
    }
  }
 
  /**
   * Get user-friendly message from generic Error
   */
  /**
   * Get user-friendly message from generic Error
   * Note: This method uses substring matching which is inherently fragile.
   * If an error message happens to contain certain keywords but isn't actually
   * that type of error, it may be misclassified. This heuristic approach
   * provides a good balance between robustness and accuracy for most common cases.
   */
  private static getUserFriendlyMessageFromError(error: Error): string {
    const message = error.message.toLowerCase();
 
    if (message.includes('timeout')) {
      return 'Request timed out. Please check your Ollama connection.';
    }
 
    if (
      message.includes('network') ||
      message.includes('fetch') ||
      message.includes('connection')
    ) {
      return 'Connection error. Please check if Ollama is running.';
    }
 
    if (message.includes('validation') || message.includes('format')) {
      return 'Invalid input. Please check your message.';
    }
 
    if (message.includes('stream') || message.includes('chunk')) {
      return 'Response too long. Please try a shorter request.';
    }
 
    if (message.includes('tool') || message.includes('function')) {
      return 'Tool execution error. Please try a different command.';
    }
 
    if (message.includes('path') || message.includes('file')) {
      return 'Invalid file path. Please use a relative path without special characters.';
    }
 
    return error.message;
  }
 
  /**
   * Create specific error instances from different error types
   */
  static createNetworkError(message: string, statusCode?: number): NetworkError {
    return new NetworkError(message, statusCode);
  }
 
  static createApiError(message: string, apiError?: any): ApiError {
    return new ApiError(message, apiError);
  }
 
  static createValidationError(
    message: string,
    field?: string,
    details?: Record<string, string>
  ): ValidationError {
    const validationDetails = field ? { field, message } : details;
    return new ValidationError(message, validationDetails);
  }
 
  static createStreamingError(message: string, chunkDetails?: any): StreamingError {
    return new StreamingError(message, chunkDetails);
  }
 
  static createToolExecutionError(message: string, toolName?: string): ToolExecutionError {
    return new ToolExecutionError(message, toolName);
  }
 
  static createPathValidationError(message: string, invalidPath?: string): PathValidationError {
    return new PathValidationError(message, invalidPath);
  }
 
  static createUnknownError(message: string): OllamaError {
    return new OllamaError(message, ErrorType.UNKNOWN_ERROR);
  }
}