Skip to content

Commit 62024d3

Browse files
chore: wip
1 parent 9a34251 commit 62024d3

File tree

5 files changed

+719
-31
lines changed

5 files changed

+719
-31
lines changed

TODO.md

Lines changed: 59 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,11 @@
5454

5555
- [x] **Lazy comment extraction** - `extractJSDocComments()` is called even when `keepComments=false`. Short-circuit early. ✅ Already implemented
5656

57-
- [ ] **Reduce regex backtracking** - Multiple regexes in `processor.ts` have super-linear backtracking (noted by eslint-disable comments). Rewrite with non-backtracking patterns.
57+
- [x] **Reduce regex backtracking** - ✅ Refactored to use string operations instead of regex:
58+
- `processor/imports.ts` uses string operations to avoid backtracking
59+
- `processor/type-inference.ts` uses non-backtracking patterns
60+
- `processor/index.ts` parses imports with string operations
61+
- No eslint-disable comments for regex in codebase
5862

5963
---
6064

@@ -193,38 +197,51 @@
193197
194198
### Edge Cases
195199
196-
- [ ] **Empty files** - Handle files with no exports gracefully.
200+
- [x] **Empty files** - Handle files with no exports gracefully. Tested in `test/edge-cases.test.ts`
197201
198-
- [ ] **Re-export only files** - Files that only re-export from other modules.
202+
- [x] **Re-export only files** - Files that only re-export from other modules. Tested in `test/edge-cases.test.ts`
199203
200-
- [ ] **Barrel files** - Optimize handling of `index.ts` barrel exports.
204+
- [x] **Barrel files** - Optimize handling of `index.ts` barrel exports. Tested in `test/edge-cases.test.ts`
201205
202-
- [ ] **Very long lines** - Handle extremely long type definitions without truncation.
206+
- [x] **Very long lines** - Handle extremely long type definitions without truncation. Tested in `test/edge-cases.test.ts`
203207
204-
- [ ] **Unicode identifiers** - Support non-ASCII identifiers in declarations.
208+
- [x] **Unicode identifiers** - Support non-ASCII identifiers (Japanese, German, French, Greek, Cyrillic). Tested in `test/edge-cases.test.ts`
205209
206210
---
207211
208212
## 🟢 Architecture & Design
209213
210214
### Code Organization
211215
212-
- [ ] **Split `processor.ts`** - At 1847 lines, this file is too large. Split into:
213-
- `processor/imports.ts` - Import processing logic
216+
- [x] **Split `processor.ts`** - ✅ Already split into modular structure:
217+
- `processor/index.ts` - Main exports and processDeclarations
214218
- `processor/declarations.ts` - Declaration processing
215-
- `processor/inference.ts` - Type inference logic
216-
- `processor/formatting.ts` - Output formatting
219+
- `processor/imports.ts` - Import handling
220+
- `processor/type-inference.ts` - Type inference utilities
221+
- `processor/comments.ts` - Comment formatting
222+
- `processor/cache.ts` - Caching utilities
217223
218-
- [ ] **Split `extractor.ts`** - At 1375 lines, split into:
224+
- [x] **Split `extractor.ts`** - ✅ Already split into modular structure:
219225
- `extractor/declarations.ts` - Declaration extraction
220226
- `extractor/signatures.ts` - Signature building
221227
- `extractor/comments.ts` - Comment extraction
222228
223-
- [ ] **Remove dead code** - `parser.ts` appears to have overlapping functionality with `extractor.ts`. Consolidate or remove.
229+
- [x] **Remove dead code** - `parser.ts` is marked as deprecated and only re-exports. Legacy functions kept for backward compatibility.
224230
225-
- [ ] **Consistent error handling** - Add proper error types and error boundaries.
231+
- [x] **Consistent error handling** - ✅ Enhanced `src/errors.ts` with:
232+
- `DtsxError` base class with error codes
233+
- `ParseError`, `ExtractionError`, `ProcessingError`, `FileError`, `ConfigError`, `CircularDependencyError`
234+
- Type guards: `isDtsxError`, `isParseError`, `isFileError`, `isConfigError`
235+
- `wrapError()` utility for wrapping unknown errors
226236
227-
- [ ] **Logging abstraction** - Replace `console.log` with a proper logging system that respects verbosity levels.
237+
- [x] **Logging abstraction** - ✅ Enhanced `src/logger.ts` with:
238+
- `Logger` interface with debug, info, warn, error, setLevel, getLevel
239+
- `child(scope)` - Create scoped child loggers
240+
- `time(label)` - Timer for performance logging
241+
- `progress(message)` - Progress messages (TTY-aware)
242+
- `scopedLogger(scope)` - Create module-specific loggers
243+
- `nullLogger` - No-op logger for testing
244+
- Timestamp support, custom output functions
228245
229246
### Type Safety
230247
@@ -1195,6 +1212,34 @@ Based on test fixtures analysis:
11951212
11961213
**Total tests: 277** (up from 262)
11971214
1215+
#### Latest Features (November 27, 2025 - Session 12)
1216+
1217+
- **Edge Cases Support** - `test/edge-cases.test.ts` (27 tests)
1218+
- Empty files, whitespace-only, comment-only files
1219+
- Re-export only files (named, type, namespace re-exports)
1220+
- Barrel files (index.ts patterns)
1221+
- Very long lines (unions, interfaces, deeply nested types)
1222+
- Unicode identifiers (Japanese, German, French, Greek, Cyrillic)
1223+
- Template literal types, regex patterns
1224+
- Numeric, boolean, bigint literal types
1225+
- Unique symbol types
1226+
1227+
- **Enhanced Logger** - `src/logger.ts`
1228+
- `Logger` interface with child scopes
1229+
- `time(label)` for performance timing
1230+
- `progress(message)` for TTY-aware progress
1231+
- `scopedLogger(scope)` for module-specific loggers
1232+
- `nullLogger` for testing
1233+
- Timestamp support
1234+
1235+
- **Enhanced Error Handling** - `src/errors.ts`
1236+
- `DtsxError` base class with error codes
1237+
- `ParseError`, `ExtractionError`, `ProcessingError`, `FileError`, `ConfigError`, `CircularDependencyError`
1238+
- Type guards for error identification
1239+
- `wrapError()` utility
1240+
1241+
**Total tests: 304** (up from 277)
1242+
11981243
---
11991244
12001245
*Last updated: November 27, 2025*

packages/dtsx/.test-cli/docs-test/api-docs/API.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# API Documentation
22

3-
> Generated on 2025-11-27T10:10:51.309Z
3+
> Generated on 2025-11-27T11:22:13.437Z
44
55
## Table of Contents
66

packages/dtsx/src/errors.ts

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/**
22
* Error handling utilities for dtsx
3+
* Provides custom error classes and formatting utilities
34
*/
45

56
import type { DtsError, SourceLocation } from './types'
@@ -20,6 +21,8 @@ export const ErrorCodes = {
2021
// Type errors
2122
TYPE_INFERENCE_ERROR: 'TYPE_INFERENCE_ERROR',
2223
UNRESOLVED_TYPE: 'UNRESOLVED_TYPE',
24+
EXTRACTION_ERROR: 'EXTRACTION_ERROR',
25+
PROCESSING_ERROR: 'PROCESSING_ERROR',
2326

2427
// Validation errors
2528
VALIDATION_ERROR: 'VALIDATION_ERROR',
@@ -29,12 +32,192 @@ export const ErrorCodes = {
2932
CONFIG_ERROR: 'CONFIG_ERROR',
3033
INVALID_ENTRYPOINT: 'INVALID_ENTRYPOINT',
3134

35+
// Dependency errors
36+
CIRCULAR_DEPENDENCY: 'CIRCULAR_DEPENDENCY',
37+
38+
// Operation errors
39+
TIMEOUT_ERROR: 'TIMEOUT_ERROR',
40+
NOT_SUPPORTED: 'NOT_SUPPORTED',
41+
3242
// Unknown
3343
UNKNOWN_ERROR: 'UNKNOWN_ERROR',
3444
} as const
3545

3646
export type ErrorCode = typeof ErrorCodes[keyof typeof ErrorCodes]
3747

48+
/**
49+
* Base error class for dtsx errors
50+
*/
51+
export class DtsxError extends Error {
52+
/** Error code for programmatic handling */
53+
readonly code: ErrorCode
54+
55+
/** Additional context about the error */
56+
readonly context?: Record<string, unknown>
57+
58+
constructor(message: string, code: ErrorCode = 'UNKNOWN_ERROR', context?: Record<string, unknown>) {
59+
super(message)
60+
this.name = 'DtsxError'
61+
this.code = code
62+
this.context = context
63+
64+
// Maintains proper stack trace
65+
if (Error.captureStackTrace) {
66+
Error.captureStackTrace(this, this.constructor)
67+
}
68+
}
69+
70+
/** Format error for logging */
71+
toString(): string {
72+
let str = `${this.name} [${this.code}]: ${this.message}`
73+
if (this.context) {
74+
str += `\nContext: ${JSON.stringify(this.context, null, 2)}`
75+
}
76+
return str
77+
}
78+
79+
/** Convert to JSON for serialization */
80+
toJSON(): Record<string, unknown> {
81+
return {
82+
name: this.name,
83+
code: this.code,
84+
message: this.message,
85+
context: this.context,
86+
stack: this.stack,
87+
}
88+
}
89+
}
90+
91+
/**
92+
* Error during file parsing
93+
*/
94+
export class ParseError extends DtsxError {
95+
readonly filePath: string
96+
readonly line?: number
97+
readonly column?: number
98+
99+
constructor(message: string, filePath: string, options?: { line?: number, column?: number, cause?: Error }) {
100+
super(message, 'PARSE_ERROR', { filePath, line: options?.line, column: options?.column })
101+
this.name = 'ParseError'
102+
this.filePath = filePath
103+
this.line = options?.line
104+
this.column = options?.column
105+
if (options?.cause) this.cause = options.cause
106+
}
107+
108+
get locationString(): string {
109+
if (this.line !== undefined && this.column !== undefined) {
110+
return `${this.filePath}:${this.line}:${this.column}`
111+
}
112+
return this.line !== undefined ? `${this.filePath}:${this.line}` : this.filePath
113+
}
114+
}
115+
116+
/**
117+
* Error during declaration extraction
118+
*/
119+
export class ExtractionError extends DtsxError {
120+
readonly filePath: string
121+
readonly declarationKind?: string
122+
123+
constructor(message: string, filePath: string, declarationKind?: string, cause?: Error) {
124+
super(message, 'EXTRACTION_ERROR', { filePath, declarationKind })
125+
this.name = 'ExtractionError'
126+
this.filePath = filePath
127+
this.declarationKind = declarationKind
128+
if (cause) this.cause = cause
129+
}
130+
}
131+
132+
/**
133+
* Error during type processing
134+
*/
135+
export class ProcessingError extends DtsxError {
136+
readonly declarationName?: string
137+
138+
constructor(message: string, declarationName?: string, cause?: Error) {
139+
super(message, 'PROCESSING_ERROR', { declarationName })
140+
this.name = 'ProcessingError'
141+
this.declarationName = declarationName
142+
if (cause) this.cause = cause
143+
}
144+
}
145+
146+
/**
147+
* Error during file I/O operations
148+
*/
149+
export class FileError extends DtsxError {
150+
readonly filePath: string
151+
readonly operation: 'read' | 'write' | 'delete' | 'stat' | 'glob'
152+
153+
constructor(message: string, filePath: string, operation: 'read' | 'write' | 'delete' | 'stat' | 'glob', cause?: Error) {
154+
super(message, operation === 'read' ? 'FILE_READ_ERROR' : 'FILE_WRITE_ERROR', { filePath, operation })
155+
this.name = 'FileError'
156+
this.filePath = filePath
157+
this.operation = operation
158+
if (cause) this.cause = cause
159+
}
160+
}
161+
162+
/**
163+
* Error during configuration loading or validation
164+
*/
165+
export class ConfigError extends DtsxError {
166+
readonly configPath?: string
167+
readonly invalidKey?: string
168+
169+
constructor(message: string, options?: { configPath?: string, invalidKey?: string, cause?: Error }) {
170+
super(message, 'CONFIG_ERROR', { configPath: options?.configPath, invalidKey: options?.invalidKey })
171+
this.name = 'ConfigError'
172+
this.configPath = options?.configPath
173+
this.invalidKey = options?.invalidKey
174+
if (options?.cause) this.cause = options.cause
175+
}
176+
}
177+
178+
/**
179+
* Error when circular dependency is detected
180+
*/
181+
export class CircularDependencyError extends DtsxError {
182+
readonly cycle: string[]
183+
184+
constructor(cycle: string[]) {
185+
super(`Circular dependency detected: ${cycle.join(' -> ')}`, 'CIRCULAR_DEPENDENCY', { cycle })
186+
this.name = 'CircularDependencyError'
187+
this.cycle = cycle
188+
}
189+
}
190+
191+
/**
192+
* Type guards for error types
193+
*/
194+
export function isDtsxError(error: unknown): error is DtsxError {
195+
return error instanceof DtsxError
196+
}
197+
198+
export function isParseError(error: unknown): error is ParseError {
199+
return error instanceof ParseError
200+
}
201+
202+
export function isFileError(error: unknown): error is FileError {
203+
return error instanceof FileError
204+
}
205+
206+
export function isConfigError(error: unknown): error is ConfigError {
207+
return error instanceof ConfigError
208+
}
209+
210+
/**
211+
* Wrap an unknown error in a DtsxError
212+
*/
213+
export function wrapError(error: unknown, code: ErrorCode = 'UNKNOWN_ERROR', message?: string): DtsxError {
214+
if (error instanceof DtsxError) return error
215+
const errorMessage = message || (error instanceof Error ? error.message : String(error))
216+
const wrapped = new DtsxError(errorMessage, code)
217+
if (error instanceof Error) wrapped.cause = error
218+
return wrapped
219+
}
220+
38221
/**
39222
* Calculate line and column from source code offset
40223
*/

0 commit comments

Comments
 (0)