CLI Internals
Design Decisions
AST Not Regex

AST Not Regex

Decision: ts-morph for File Modifications


The Decision

Use Abstract Syntax Tree (AST) manipulation via ts-morph instead of regex-based string replacement.

// We do this:
const sourceFile = project.createSourceFile(path, content);
sourceFile.addImportDeclaration({
  moduleSpecifier: '@/lib/query',
  namedImports: ['QueryProvider']
});
 
// Not this:
content = content.replace(
  /^/,
  "import { QueryProvider } from '@/lib/query';\n"
);

Rationale

1. Reliability

AST manipulation is 100% accurate for valid TypeScript.

Regex approach:

// Breaks on these variations:
import{QueryProvider}from'@/lib/query';  // No spaces
import { 
  QueryProvider 
} from '@/lib/query';  // Multi-line
import type { QueryProvider } from '@/lib/query';  // Type import

AST approach: Handles all valid TypeScript syntax.

2. Complexity Handling

Can handle complex TypeScript features:

  • Generics
  • JSX
  • Decorators
  • Type annotations

3. Code Preservation

Preserves:

  • Comments
  • Formatting (mostly)
  • Code structure

Alternatives Considered

Regex-Based (Rejected)

Why rejected:

  • Too brittle
  • Can't handle edge cases
  • High failure rate on complex files

String Templates (Rejected)

Why rejected:

  • Overwrites existing code
  • Can't merge intelligently

Trade-offs

Cost: Performance (AST parsing ~200ms per file)
Benefit: Reliability (95%+ success rate vs ~60% with regex)

Verdict: Reliability worth the cost.


Back to Design Decisions →