|
| 1 | +/** |
| 2 | + * Configuration related errors |
| 3 | + */ |
| 4 | + |
| 5 | +import { ErrorCategory, ErrorSeverity, ErrorContext } from "../types/error-types" |
| 6 | +import { CLIError } from "./CLIError" |
| 7 | + |
| 8 | +export class ConfigurationError extends CLIError { |
| 9 | + readonly category = ErrorCategory.CONFIGURATION |
| 10 | + readonly severity = ErrorSeverity.HIGH |
| 11 | + readonly isRecoverable = true |
| 12 | + |
| 13 | + constructor( |
| 14 | + message: string, |
| 15 | + code: string, |
| 16 | + public readonly configPath?: string, |
| 17 | + public readonly configKey?: string, |
| 18 | + context?: ErrorContext, |
| 19 | + cause?: Error, |
| 20 | + ) { |
| 21 | + super(message, code, context, cause) |
| 22 | + } |
| 23 | + |
| 24 | + override getSuggestedActions(): string[] { |
| 25 | + const actions = [ |
| 26 | + "Check configuration file syntax", |
| 27 | + "Verify required settings are present", |
| 28 | + "Reset to default configuration", |
| 29 | + ] |
| 30 | + |
| 31 | + if (this.configPath) { |
| 32 | + actions.push(`Check configuration file: ${this.configPath}`) |
| 33 | + } |
| 34 | + |
| 35 | + if (this.configKey) { |
| 36 | + actions.push(`Verify configuration key "${this.configKey}" is correct`) |
| 37 | + } |
| 38 | + |
| 39 | + return actions |
| 40 | + } |
| 41 | + |
| 42 | + override getDocumentationLinks(): string[] { |
| 43 | + return [ |
| 44 | + "https://docs.npmjs.com/cli/v8/configuring-npm/npmrc", |
| 45 | + "https://nodejs.org/api/fs.html#fs_fs_readfilesync_path_options", |
| 46 | + ] |
| 47 | + } |
| 48 | + |
| 49 | + override getUserFriendlyMessage(): string { |
| 50 | + if (this.configPath && this.configKey) { |
| 51 | + return `Configuration error in "${this.configPath}" for key "${this.configKey}": ${this.message}` |
| 52 | + } |
| 53 | + if (this.configPath) { |
| 54 | + return `Configuration error in "${this.configPath}": ${this.message}` |
| 55 | + } |
| 56 | + return `Configuration error: ${this.message}` |
| 57 | + } |
| 58 | +} |
| 59 | + |
| 60 | +// Specific configuration error types |
| 61 | +export class InvalidConfigSyntaxError extends ConfigurationError { |
| 62 | + constructor(configPath: string, line?: number, context?: ErrorContext, cause?: Error) { |
| 63 | + const message = line |
| 64 | + ? `Invalid syntax in configuration file at line ${line}` |
| 65 | + : "Invalid syntax in configuration file" |
| 66 | + |
| 67 | + super(message, "CONFIG_INVALID_SYNTAX", configPath, undefined, context, cause) |
| 68 | + } |
| 69 | + |
| 70 | + override getSuggestedActions(): string[] { |
| 71 | + return [ |
| 72 | + "Check JSON/YAML syntax in configuration file", |
| 73 | + "Validate configuration with online JSON/YAML validator", |
| 74 | + "Check for missing commas, brackets, or quotes", |
| 75 | + "Reset configuration to default values", |
| 76 | + ] |
| 77 | + } |
| 78 | +} |
| 79 | + |
| 80 | +export class MissingConfigError extends ConfigurationError { |
| 81 | + constructor(configPath: string, context?: ErrorContext, cause?: Error) { |
| 82 | + super(`Configuration file not found: ${configPath}`, "CONFIG_NOT_FOUND", configPath, undefined, context, cause) |
| 83 | + } |
| 84 | + |
| 85 | + override getSuggestedActions(): string[] { |
| 86 | + return [ |
| 87 | + `Create configuration file at: ${this.configPath}`, |
| 88 | + "Run initialization command to create default config", |
| 89 | + "Check if configuration file path is correct", |
| 90 | + "Use --config flag to specify configuration file location", |
| 91 | + ] |
| 92 | + } |
| 93 | +} |
| 94 | + |
| 95 | +export class InvalidConfigValueError extends ConfigurationError { |
| 96 | + constructor( |
| 97 | + configKey: string, |
| 98 | + expectedType: string, |
| 99 | + actualValue: any, |
| 100 | + configPath?: string, |
| 101 | + context?: ErrorContext, |
| 102 | + cause?: Error, |
| 103 | + ) { |
| 104 | + super( |
| 105 | + `Invalid value for "${configKey}": expected ${expectedType}, got ${typeof actualValue}`, |
| 106 | + "CONFIG_INVALID_VALUE", |
| 107 | + configPath, |
| 108 | + configKey, |
| 109 | + context, |
| 110 | + cause, |
| 111 | + ) |
| 112 | + } |
| 113 | + |
| 114 | + override getSuggestedActions(): string[] { |
| 115 | + return [ |
| 116 | + `Check the value type for configuration key "${this.configKey}"`, |
| 117 | + "Refer to documentation for valid configuration values", |
| 118 | + "Use configuration validation tool", |
| 119 | + "Reset this configuration value to default", |
| 120 | + ] |
| 121 | + } |
| 122 | +} |
| 123 | + |
| 124 | +export class MissingRequiredConfigError extends ConfigurationError { |
| 125 | + constructor(configKey: string, configPath?: string, context?: ErrorContext, cause?: Error) { |
| 126 | + super( |
| 127 | + `Required configuration key "${configKey}" is missing`, |
| 128 | + "CONFIG_MISSING_REQUIRED", |
| 129 | + configPath, |
| 130 | + configKey, |
| 131 | + context, |
| 132 | + cause, |
| 133 | + ) |
| 134 | + } |
| 135 | + |
| 136 | + override getSuggestedActions(): string[] { |
| 137 | + return [ |
| 138 | + `Add required configuration key "${this.configKey}"`, |
| 139 | + "Check documentation for required configuration options", |
| 140 | + "Run setup command to configure required settings", |
| 141 | + "Use environment variables as alternative configuration", |
| 142 | + ] |
| 143 | + } |
| 144 | +} |
0 commit comments