CLI Internals
Architecture
Layer 6: Modifiers

Layer 6: Modifier Layer

AST-Based File Manipulation

Modifiers perform complex file modifications using Abstract Syntax Tree (AST) manipulation via ts-morph.


Purpose

Provide high-level file modification operations that are:

  • Reliable (AST, not regex)
  • Accurate (Handles complex TypeScript)
  • Safe (Preserves code structure)
  • Simple (For blueprint authors)

Available Modifiers

ts-module-enhancer

Add imports and statements to TypeScript files.

Usage:

{
  type: 'ENHANCE_FILE',
  path: 'src/app/layout.tsx',
  modifier: 'ts-module-enhancer',
  params: {
    importsToAdd: [
      { name: 'QueryProvider', from: '@/lib/query-client' }
    ],
    statementsToAppend: [
      { type: 'const', content: 'export const foo = 1;' }
    ]
  }
}

jsx-children-wrapper

Wrap {children} with provider components.

Usage:

{
  type: 'ENHANCE_FILE',
  path: 'src/app/layout.tsx',
  modifier: 'jsx-children-wrapper',
  params: {
    wrapperComponent: 'QueryProvider',
    importFrom: '@/lib/query-client'
  }
}

Result:

// Before:
<body>{'{'children{'}'}</body>
 
// After:
<body>
  <QueryProvider>{'{'children{'}'}</QueryProvider>
</body>

package-json-merger

Deep merge package.json.

tsconfig-enhancer

Merge tsconfig.json.

js-export-wrapper

Wrap exports with HOCs.


AST Manipulation Example

// src/core/services/file-system/modifiers/ts-module-enhancer.ts
async execute(filePath, params, context, vfs) {
  // 1. Read from VFS
  const content = await vfs.readFile(filePath);
  
  // 2. Parse with ts-morph
  const project = new Project({ useInMemoryFileSystem: true });
  const sourceFile = project.createSourceFile(filePath, content);
  
  // 3. Add imports via AST
  params.importsToAdd.forEach(imp => {
    sourceFile.addImportDeclaration({
      moduleSpecifier: imp.from,
      namedImports: [imp.name]
    });
  });
  
  // 4. Get modified content
  const modifiedContent = sourceFile.getFullText();
  
  // 5. Write back to VFS
  await vfs.writeFile(filePath, modifiedContent);
  
  return { success: true };
}

Why AST?: Reliably handles all TypeScript syntax, preserves formatting, avoids regex brittleness.


Next: Design Decisions: AST not Regex →