|
| 1 | +# Exception |
| 2 | + |
| 3 | +The Exception class extends the Exception class from `@stackpress/lib` to provide enhanced error handling specific to the idea parser library. It includes position information and better error reporting for parsing failures. |
| 4 | + |
| 5 | +```typescript |
| 6 | +import { Exception } from '@stackpress/idea-parser'; |
| 7 | +``` |
| 8 | + |
| 9 | + 1. [Overview](#1-overview) |
| 10 | + 2. [Usage Examples](#2-usage-examples) |
| 11 | + 3. [Integration with AST](#3-integration-with-ast) |
| 12 | + 4. [Error Recovery](#4-error-recovery) |
| 13 | + 5. [Language Server Integration](#5-language-server-integration) |
| 14 | + 6. [Inherited Features](#6-inherited-features) |
| 15 | + 7. [Best Practices](#7-best-practices) |
| 16 | + |
| 17 | +## 1. Overview |
| 18 | + |
| 19 | +Exception is a specialized error class that extends the base Exception class with additional functionality for parser-specific error handling. It automatically includes position information when parsing fails, making it easier to identify and fix syntax errors in schema files. |
| 20 | + |
| 21 | +## 2. Usage Examples |
| 22 | + |
| 23 | +The following examples demonstrates how to use exceptions. |
| 24 | + |
| 25 | +### 2.1. Basic Error Handling |
| 26 | + |
| 27 | +```typescript |
| 28 | +import { parse, Exception } from '@stackpress/idea-parser'; |
| 29 | + |
| 30 | +try { |
| 31 | + const result = parse('invalid schema syntax'); |
| 32 | +} catch (error) { |
| 33 | + if (error instanceof Exception) { |
| 34 | + console.log('Parser error:', error.message); |
| 35 | + console.log('Error position:', error.start, '-', error.end); |
| 36 | + console.log('Stack trace:', error.stack); |
| 37 | + } |
| 38 | +} |
| 39 | +``` |
| 40 | + |
| 41 | +### 2.2. Position Information |
| 42 | + |
| 43 | +Exception includes position information to help locate errors in the source code: |
| 44 | + |
| 45 | +```typescript |
| 46 | +import { EnumTree, Exception } from '@stackpress/idea-parser'; |
| 47 | + |
| 48 | +try { |
| 49 | + // Missing closing brace |
| 50 | + EnumTree.parse('enum Status { ACTIVE "Active"'); |
| 51 | +} catch (error) { |
| 52 | + if (error instanceof Exception) { |
| 53 | + console.log('Error message:', error.message); |
| 54 | + console.log('Error starts at character:', error.start); |
| 55 | + console.log('Error ends at character:', error.end); |
| 56 | + |
| 57 | + // Can be used for syntax highlighting in editors |
| 58 | + const errorRange = { start: error.start, end: error.end }; |
| 59 | + } |
| 60 | +} |
| 61 | +``` |
| 62 | + |
| 63 | +### 2.3. Common Error Scenarios |
| 64 | + |
| 65 | +The following examples demonstrate common error scenarios that can occur during parsing. Each scenario shows the type of error that triggers an Exception and how to handle it appropriately. |
| 66 | + |
| 67 | +#### 2.3.1. Syntax Errors |
| 68 | + |
| 69 | +Syntax errors occur when the parser encounters invalid syntax in the schema code. These are the most common type of parsing errors and typically involve missing brackets, braces, or other structural elements. |
| 70 | + |
| 71 | +```typescript |
| 72 | +try { |
| 73 | + parse('enum Status { ACTIVE "Active"'); // Missing closing brace |
| 74 | +} catch (error) { |
| 75 | + console.log(error.message); // "Unexpected end of input expecting }" |
| 76 | +} |
| 77 | +``` |
| 78 | + |
| 79 | +#### 2.3.2. Invalid Token Types |
| 80 | + |
| 81 | +Invalid token type errors occur when the parser encounters tokens that don't match the expected grammar rules. This commonly happens with incorrect capitalization or using reserved keywords incorrectly. |
| 82 | + |
| 83 | +```typescript |
| 84 | +try { |
| 85 | + parse('model user { id String }'); // Invalid - should be capitalized |
| 86 | +} catch (error) { |
| 87 | + console.log(error.message); // "Expected CapitalIdentifier but got something else" |
| 88 | +} |
| 89 | +``` |
| 90 | + |
| 91 | +#### 2.3.3. Unknown References |
| 92 | + |
| 93 | +Unknown reference errors occur when the parser encounters references to types, properties, or other identifiers that haven't been defined in the schema. This typically happens when referencing custom types or properties that don't exist. |
| 94 | + |
| 95 | +```typescript |
| 96 | +try { |
| 97 | + parse('model User { name String @field.input(UnknownProp) }'); |
| 98 | +} catch (error) { |
| 99 | + console.log(error.message); // "Unknown reference UnknownProp" |
| 100 | +} |
| 101 | +``` |
| 102 | + |
| 103 | +#### 2.3.4. Duplicate Declarations |
| 104 | + |
| 105 | +Duplicate declaration errors occur when the same identifier is declared multiple times within the same scope. This prevents ambiguity in the schema and ensures each type, enum, or model has a unique name. |
| 106 | + |
| 107 | +```typescript |
| 108 | +try { |
| 109 | + parse(` |
| 110 | + enum Status { ACTIVE "Active" } |
| 111 | + enum Status { INACTIVE "Inactive" } |
| 112 | + `); |
| 113 | +} catch (error) { |
| 114 | + console.log(error.message); // "Duplicate Status" |
| 115 | +} |
| 116 | +``` |
| 117 | + |
| 118 | +## 3. Integration with AST |
| 119 | + |
| 120 | +All AST classes throw Exception when parsing fails: |
| 121 | + |
| 122 | +```typescript |
| 123 | +import { SchemaTree, EnumTree, ModelTree, Exception } from '@stackpress/idea-parser'; |
| 124 | + |
| 125 | +// Any parsing operation can throw Exception |
| 126 | +try { |
| 127 | + const schema = SchemaTree.parse(schemaCode); |
| 128 | + const enumAST = EnumTree.parse(enumCode); |
| 129 | + const modelAST = ModelTree.parse(modelCode); |
| 130 | +} catch (error) { |
| 131 | + if (error instanceof Exception) { |
| 132 | + // Handle parser-specific errors |
| 133 | + console.error('Parsing failed:', error.message); |
| 134 | + } else { |
| 135 | + // Handle other types of errors |
| 136 | + console.error('Unexpected error:', error); |
| 137 | + } |
| 138 | +} |
| 139 | +``` |
| 140 | + |
| 141 | +## 4. Error Recovery |
| 142 | + |
| 143 | +While Exception indicates parsing failure, you can implement error recovery strategies: |
| 144 | + |
| 145 | +```typescript |
| 146 | +import { parse, Exception } from '@stackpress/idea-parser'; |
| 147 | + |
| 148 | +function parseWithFallback(code: string, fallbackCode?: string) { |
| 149 | + try { |
| 150 | + return parse(code); |
| 151 | + } catch (error) { |
| 152 | + if (error instanceof Exception && fallbackCode) { |
| 153 | + console.warn('Primary parsing failed, trying fallback:', error.message); |
| 154 | + return parse(fallbackCode); |
| 155 | + } |
| 156 | + throw error; // Re-throw if no fallback or different error type |
| 157 | + } |
| 158 | +} |
| 159 | +``` |
| 160 | + |
| 161 | +## 5. Language Server Integration |
| 162 | + |
| 163 | +Exception's position information makes it ideal for language server implementations: |
| 164 | + |
| 165 | +```typescript |
| 166 | +import { parse, Exception } from '@stackpress/idea-parser'; |
| 167 | + |
| 168 | +function validateSchema(code: string) { |
| 169 | + try { |
| 170 | + parse(code); |
| 171 | + return { valid: true, errors: [] }; |
| 172 | + } catch (error) { |
| 173 | + if (error instanceof Exception) { |
| 174 | + return { |
| 175 | + valid: false, |
| 176 | + errors: [{ |
| 177 | + message: error.message, |
| 178 | + range: { |
| 179 | + start: error.start, |
| 180 | + end: error.end |
| 181 | + }, |
| 182 | + severity: 'error' |
| 183 | + }] |
| 184 | + }; |
| 185 | + } |
| 186 | + throw error; |
| 187 | + } |
| 188 | +} |
| 189 | +``` |
| 190 | + |
| 191 | +## 6. Inherited Features |
| 192 | + |
| 193 | +Since Exception extends the base Exception class from `@stackpress/lib`, it inherits all the enhanced error handling features: |
| 194 | + |
| 195 | +- Template-based error messages |
| 196 | +- Enhanced stack trace parsing |
| 197 | +- Position information support |
| 198 | +- HTTP status code integration |
| 199 | +- Validation error aggregation |
| 200 | + |
| 201 | +For more details on the base Exception functionality, refer to the [@stackpress/lib Exception documentation](https://github.com/stackpress/lib#exception). |
| 202 | + |
| 203 | +## 7. Best Practices |
| 204 | + |
| 205 | +The following best practices help ensure robust error handling when working with the Exception class. These guidelines promote consistent error handling patterns and improve debugging capabilities. |
| 206 | + |
| 207 | +### 7.1. Always Check Error Type |
| 208 | + |
| 209 | +Always check if an error is an instance of Exception before accessing parser-specific properties. This ensures your code can handle both parser errors and other types of errors gracefully. |
| 210 | + |
| 211 | +```typescript |
| 212 | +try { |
| 213 | + parse(schemaCode); |
| 214 | +} catch (error) { |
| 215 | + if (error instanceof Exception) { |
| 216 | + // Handle parser errors specifically |
| 217 | + handleParserError(error); |
| 218 | + } else { |
| 219 | + // Handle other errors (network, file system, etc.) |
| 220 | + handleGenericError(error); |
| 221 | + } |
| 222 | +} |
| 223 | +``` |
| 224 | + |
| 225 | +### 7.2. Use Position Information |
| 226 | + |
| 227 | +Leverage the position information provided by Exception to create helpful error displays and debugging tools. This information is particularly useful for IDE integrations and syntax highlighting. |
| 228 | + |
| 229 | +```typescript |
| 230 | +function highlightError(code: string, error: Exception) { |
| 231 | + const lines = code.split('\n'); |
| 232 | + let currentPos = 0; |
| 233 | + |
| 234 | + for (let i = 0; i < lines.length; i++) { |
| 235 | + const lineEnd = currentPos + lines[i].length; |
| 236 | + |
| 237 | + if (error.start >= currentPos && error.start <= lineEnd) { |
| 238 | + const lineStart = error.start - currentPos; |
| 239 | + const lineEnd = Math.min(error.end - currentPos, lines[i].length); |
| 240 | + |
| 241 | + console.log(`Line ${i + 1}: ${lines[i]}`); |
| 242 | + console.log(' '.repeat(lineStart + 8) + '^'.repeat(lineEnd - lineStart)); |
| 243 | + break; |
| 244 | + } |
| 245 | + |
| 246 | + currentPos = lineEnd + 1; // +1 for newline |
| 247 | + } |
| 248 | +} |
| 249 | +``` |
| 250 | + |
| 251 | +### 7.3. Provide Helpful Error Messages |
| 252 | + |
| 253 | +Enhance error messages with additional context such as file names, line numbers, or suggestions for fixing the error. This makes debugging easier and improves the developer experience. |
| 254 | + |
| 255 | +```typescript |
| 256 | +function parseWithContext(code: string, filename?: string) { |
| 257 | + try { |
| 258 | + return parse(code); |
| 259 | + } catch (error) { |
| 260 | + if (error instanceof Exception) { |
| 261 | + const context = filename ? ` in ${filename}` : ''; |
| 262 | + throw new Exception( |
| 263 | + `Parse error${context}: ${error.message}`, |
| 264 | + error.code |
| 265 | + ).withPosition(error.start, error.end); |
| 266 | + } |
| 267 | + throw error; |
| 268 | + } |
| 269 | +} |
| 270 | +``` |
0 commit comments