Guide to creating custom solution generators.

Overview

Solution generators create optimized code fixes for detected issues. Each generator handles specific issue types.

Base Class

abstract class BaseSolutionGenerator {
  abstract name: string;
  abstract generateSolutions(issue: Issue, context: AnalysisContext): Promise<Solution[]>;
  
  protected generateTransformationBasedSolutions(
    issue: Issue,
    context: AnalysisContext,
    strategies: TransformationStrategy[]
  ): Solution[];
}

Creating a Generator

// src/generators/my-solution-generator.ts
import { BaseSolutionGenerator, TransformationStrategy } from './base-generator';
import { Issue, Solution, AnalysisContext } from '../types';

export class MySolutionGenerator extends BaseSolutionGenerator {
  name = 'My Solution Generator';

  async generateSolutions(issue: Issue, context: AnalysisContext): Promise<Solution[]> {
    const strategies: TransformationStrategy[] = [
      {
        name: 'my-optimization',
        description: 'Apply custom optimization',
        fitness: 85,
        apply: (code, pattern, ctx) => this.applyOptimization(code, pattern)
      }
    ];
    
    return this.generateTransformationBasedSolutions(issue, context, strategies);
  }

  private applyOptimization(code: string, pattern: CodePattern) {
    // Transform the code
    const optimizedCode = code.replace(/pattern/, 'replacement');
    
    return {
      success: true,
      code: optimizedCode,
      description: 'Applied optimization',
      transformationType: 'my-optimization',
      preservedElements: ['variable names', 'function structure']
    };
  }
}

Registering Generator

// In CodeAnalyzer constructor
this.generators.set('my_issue_type', new MySolutionGenerator());

Transformation Strategy

interface TransformationStrategy {
  name: string;           // Strategy identifier
  description: string;    // Human-readable description
  fitness: number;        // Base fitness score (0-100)
  apply: (
    originalCode: string,
    pattern: CodePattern,
    context: AnalysisContext
  ) => TransformationResult;
}

interface TransformationResult {
  success: boolean;
  code: string;
  description: string;
  transformationType: string;
  preservedElements: string[];
}

preservedElements should list the identifiers and structures your transformation genuinely kept from the original — it determines the solution’s risk rating, not just its documentation.

Code Pattern Analysis

interface CodePattern {
  type: 'loop-with-calls' | 'chained-methods' | 'repeated-access' | 'nested-loop' | 'unknown';
  loopVariable?: string;
  iteratedCollection?: string;
  repeatedCalls: string[];
  originalStructure: string;
}

Framework information is not part of CodePattern. Detectors that determine a framework record it on the issue under estimatedImpact.metrics.framework, which is where framework-aware generators read it from.

Best Practices

  1. Preserve Original Structure - Keep variable names and code organization
  2. Expect Validation - generateTransformationBasedSolutions runs isValidCode() on every result and silently skips comment-only output, so a strategy that returns explanation rather than code produces nothing
  3. Provide Multiple Strategies - Offer different optimization approaches
  4. Calculate Accurate Fitness - Consider performance, complexity, maintainability
  5. Handle Edge Cases - Check for empty code, missing patterns