Skip to content

Instantly share code, notes, and snippets.

@wickedev
Created October 31, 2025 04:55
Show Gist options
  • Select an option

  • Save wickedev/0d9f631db0ee44c9d28109cd5f340ac7 to your computer and use it in GitHub Desktop.

Select an option

Save wickedev/0d9f631db0ee44c9d28109cd5f340ac7 to your computer and use it in GitHub Desktop.
Kiro for Claude Code

Design Document

Overview

Code Generator는 Parser가 생성한 Protobuf AST를 받아서 타입 안전한 TypeScript 코드를 생성하는 핵심 컴포넌트입니다. Generator는 gRPC 서비스 스텁, 메시지 타입 정의, React Hook 통합 코드를 생성하며, google-protobuf 라이브러리와 @improbable-eng/grpc-web를 활용한 런타임 직렬화/역직렬화를 지원합니다. 생성된 코드는 Promise API와 React Hook API 두 가지 사용 패턴을 모두 지원합니다.

Architecture

High-Level Architecture

graph TD
    A[Parser AST] --> B[Code Generator]
    B --> C[Template Engine]
    B --> D[Type Registry]
    B --> E[Import Resolver]

    C --> F[Service Stub Generator]
    C --> G[Message Type Generator]
    C --> H[React Hook Generator]

    F --> I[Promise API Code]
    G --> J[TypeScript Interfaces]
    H --> K[React Hook Code]

    I --> L[Generated TypeScript Module]
    J --> L
    K --> L

    M[google-protobuf] --> L
    N["@"improbable-eng/grpc-web] --> L
Loading

Project Structure

packages/generator/
├── src/
│   ├── core/
│   │   ├── Generator.ts           # Main generator interface
│   │   ├── CodeBuilder.ts         # Code building utilities
│   │   └── TemplateEngine.ts      # Template processing
│   ├── generators/
│   │   ├── ServiceGenerator.ts    # Service stub generation
│   │   ├── MessageGenerator.ts    # Message type generation
│   │   ├── ReactHookGenerator.ts  # React hook generation
│   │   └── TypeGenerator.ts       # Common type utilities
│   ├── templates/
│   │   ├── service.hbs           # Service stub templates
│   │   ├── message.hbs           # Message type templates
│   │   └── hooks.hbs             # React hook templates
│   ├── utils/
│   │   ├── TypeMapper.ts         # Proto to TS type mapping
│   │   ├── NameResolver.ts       # Name resolution utilities
│   │   └── ImportManager.ts      # Import statement management
│   └── index.ts                  # Main export
├── tests/
│   ├── fixtures/                 # Test proto files and expected outputs
│   ├── generators/               # Generator unit tests
│   └── integration/              # End-to-end tests
└── package.json

Component Layers

  1. Core Layer: 메인 Generator 인터페이스와 코드 빌딩 유틸리티
  2. Generator Layer: 각 타입별 코드 생성기 (Service, Message, React Hook)
  3. Template Layer: Handlebars 기반 코드 템플릿
  4. Utility Layer: 타입 매핑, 네임 해결, Import 관리

Components and Interfaces

Core Generator Components

1. Generator

interface Generator {
  generateCode(ast: ProtoFile, options: GeneratorOptions): GeneratedCode;
  generateServiceStub(service: ServiceDefinition): string;
  generateMessageTypes(messages: MessageDefinition[]): string;
  generateReactHooks(services: ServiceDefinition[]): string;
}

interface GeneratorOptions {
  outputFormat: 'esm' | 'cjs';
  includeReactHooks: boolean;
  optimizeForSize: boolean;
  customTemplates?: Record<string, string>;
}

interface GeneratedCode {
  code: string;
  imports: ImportStatement[];
  exports: ExportStatement[];
  sourceMap?: string;
}

2. ServiceGenerator

interface ServiceGenerator {
  generateStub(service: ServiceDefinition, options: ServiceOptions): ServiceStubCode;
  generateMethod(method: MethodDefinition): MethodCode;
  generateStreamingMethod(method: MethodDefinition): StreamingMethodCode;
}

interface ServiceStubCode {
  className: string;
  methods: MethodCode[];
  imports: string[];
  dependencies: string[];
}

interface MethodCode {
  name: string;
  signature: string;
  implementation: string;
  documentation: string;
}

3. MessageGenerator

interface MessageGenerator {
  generateInterface(message: MessageDefinition): TypeScriptInterface;
  generateClass(message: MessageDefinition): TypeScriptClass;
  generateSerializer(message: MessageDefinition): SerializerCode;
}

interface TypeScriptInterface {
  name: string;
  properties: PropertyDefinition[];
  nestedTypes: TypeScriptInterface[];
  documentation: string;
}

interface SerializerCode {
  serializeMethod: string;
  deserializeMethod: string;
  dependencies: string[];
}

4. ReactHookGenerator

interface ReactHookGenerator {
  generateHookStub(service: ServiceDefinition): ReactHookStubCode;
  generateHook(method: MethodDefinition): ReactHookCode;
  generateSuspenseHook(method: MethodDefinition): SuspenseHookCode;
}

interface ReactHookStubCode {
  className: string;
  hooks: ReactHookCode[];
  imports: string[];
}

interface ReactHookCode {
  hookName: string;
  signature: string;
  implementation: string;
  returnType: string;
}

Data Models

Code Generation Models

GeneratedModule

interface GeneratedModule {
  imports: ImportStatement[];
  types: TypeDefinition[];
  classes: ClassDefinition[];
  exports: ExportStatement[];
  sourceMap?: SourceMapData;
}

interface ImportStatement {
  source: string;
  imports: string[];
  isDefault: boolean;
  isNamespace: boolean;
}

interface ExportStatement {
  name: string;
  type: 'class' | 'interface' | 'type' | 'const';
  isDefault: boolean;
}

TypeDefinition

interface TypeDefinition {
  name: string;
  kind: 'interface' | 'type' | 'enum';
  properties?: PropertyDefinition[];
  values?: EnumValueDefinition[];
  generics?: string[];
  documentation: string;
}

interface PropertyDefinition {
  name: string;
  type: string;
  optional: boolean;
  readonly: boolean;
  documentation: string;
}

ClassDefinition

interface ClassDefinition {
  name: string;
  extends?: string;
  implements?: string[];
  constructor: ConstructorDefinition;
  methods: MethodDefinition[];
  properties: PropertyDefinition[];
  documentation: string;
}

interface ConstructorDefinition {
  parameters: ParameterDefinition[];
  implementation: string;
}

interface MethodDefinition {
  name: string;
  parameters: ParameterDefinition[];
  returnType: string;
  implementation: string;
  isAsync: boolean;
  isStatic: boolean;
  documentation: string;
}

Code Generation Strategy

Service Stub Generation

Promise API Pattern

// Generated service stub example
export class GreetingStub {
  constructor(private client: Client) {}

  async greeting(request: GreetingRequest): Promise<GreetingResponse> {
    const serialized = GreetingRequest.encode(request).finish();
    const response = await this.client.unaryCall('/greeting.Greeting/Greeting', serialized);
    return GreetingResponse.decode(response);
  }
}

React Hook API Pattern

// Generated React hook stub example
export class GreetingHookStub {
  constructor(private client: Client) {}

  useGreeting(request: GreetingRequest): GreetingResponse {
    const [data, setData] = useState<GreetingResponse>();
    const [error, setError] = useState<Error>();

    if (!data && !error) {
      throw this.greeting(request).then(setData).catch(setError);
    }

    if (error) throw error;
    return data!;
  }
}

Message Type Generation

Interface Generation

// Generated message interface
export interface GreetingRequest {
  name: string;
}

export interface GreetingResponse {
  message: string;
}

Serialization Code Generation

// Generated serialization utilities
export namespace GreetingRequest {
  export function encode(message: GreetingRequest): Uint8Array {
    const writer = new protobuf.Writer();
    if (message.name) {
      writer.uint32(10).string(message.name);
    }
    return writer.finish();
  }

  export function decode(input: Uint8Array): GreetingRequest {
    const reader = new protobuf.Reader(input);
    const message: GreetingRequest = { name: '' };

    while (reader.pos < reader.len) {
      const tag = reader.uint32();
      switch (tag >>> 3) {
        case 1:
          message.name = reader.string();
          break;
        default:
          reader.skipType(tag & 7);
          break;
      }
    }
    return message;
  }
}

Template System

Handlebars Templates

Service Template Structure

{{#each services}}
export class {{name}}Stub {
  constructor(private client: Client) {}

  {{#each methods}}
  {{#if isStreaming}}
  {{> streamingMethod}}
  {{else}}
  {{> unaryMethod}}
  {{/if}}
  {{/each}}
}

{{#if includeReactHooks}}
export class {{name}}HookStub {
  constructor(private client: Client) {}

  {{#each methods}}
  {{> reactHook}}
  {{/each}}
}
{{/if}}
{{/each}}

Message Template Structure

{{#each messages}}
export interface {{name}} {
  {{#each fields}}
  {{name}}{{#if optional}}?{{/if}}: {{type}}{{#if repeated}}[]{{/if}}
  {{/each}}
}

export namespace {{name}} {
  export function encode(message: {{name}}): Uint8Array {
    {{> encodeImplementation}}
  }

  export function decode(input: Uint8Array): {{name}} {
    {{> decodeImplementation}}
  }
}
{{/each}}

Error Handling

Generation Error Types

interface GenerationError {
  type: 'template' | 'type-mapping' | 'validation' | 'dependency';
  message: string;
  location?: ASTLocation;
  severity: 'error' | 'warning';
  suggestions?: string[];
}

Error Handling Strategy

  1. Template Errors: Handlebars 템플릿 처리 오류

    • 템플릿 문법 오류
    • 누락된 데이터 바인딩
    • 순환 참조
  2. Type Mapping Errors: Proto 타입을 TypeScript 타입으로 매핑 실패

    • 지원하지 않는 타입
    • 순환 타입 참조
    • 네임스페이스 충돌
  3. Validation Errors: 생성된 코드 검증 실패

    • TypeScript 컴파일 오류
    • 런타임 오류 가능성
    • 타입 안전성 위반

Testing Strategy

Unit Testing

Generator Core Tests

describe('Generator', () => {
  test('should generate service stub from AST', () => {
    const ast = createServiceAST('Greeting', [
      { name: 'SayHello', input: 'HelloRequest', output: 'HelloReply' },
    ]);
    const result = generator.generateServiceStub(ast.services[0]);
    expect(result).toContain('class GreetingStub');
    expect(result).toContain('async sayHello(');
  });
});

Template Engine Tests

describe('TemplateEngine', () => {
  test('should process service template correctly', () => {
    const data = { name: 'Greeting', methods: [{ name: 'sayHello' }] };
    const result = templateEngine.render('service', data);
    expect(result).toContain('export class GreetingStub');
  });
});

Integration Testing

End-to-End Generation Tests

describe('E2E Generation', () => {
  test('should generate working code from proto file', async () => {
    const protoContent = `
      service Greeting {
        rpc SayHello (HelloRequest) returns (HelloReply);
      }
    `;
    const ast = await parser.parseContent(protoContent);
    const code = generator.generateCode(ast);

    // Compile generated code
    const compiled = await compileTypeScript(code.code);
    expect(compiled.errors).toHaveLength(0);

    // Test runtime behavior
    const module = await importGeneratedModule(compiled.output);
    expect(module.GreetingStub).toBeDefined();
  });
});

Performance Testing

Code Generation Benchmarks

describe('Performance', () => {
  test('should generate code for large proto within time limit', () => {
    const largeAST = createLargeProtoAST(100); // 100 services
    const startTime = Date.now();
    const result = generator.generateCode(largeAST);
    const duration = Date.now() - startTime;
    expect(duration).toBeLessThan(10000); // 10초 이내
    expect(result.code.length).toBeGreaterThan(0);
  });
});

Implementation Phases

Phase 1: Core Infrastructure

  • Generator 인터페이스 및 기본 구조 구현
  • Template Engine 설정 (Handlebars)
  • 기본 타입 매핑 시스템

Phase 2: Service Generation

  • 서비스 스텁 생성기 구현
  • Promise API 코드 생성
  • 기본 RPC 메서드 지원

Phase 3: Message Generation

  • 메시지 인터페이스 생성
  • google-protobuf 직렬화 코드 생성
  • 중첩 타입 및 enum 지원

Phase 4: React Integration

  • React Hook 생성기 구현
  • Suspense 호환 Hook 생성
  • Error Boundary 통합

Phase 5: Advanced Features

  • 스트리밍 RPC 지원
  • 커스텀 옵션 처리
  • Import 의존성 해결

Phase 6: Optimization & Testing

  • 코드 최적화 및 Tree-shaking 지원
  • 포괄적인 테스트 스위트
  • 성능 벤치마크 및 최적화

Requirements Document

Introduction

Hallow gRPC 프로젝트의 코드 생성기(Generator)를 구현합니다. 이 컴포넌트는 Parser가 생성한 Protobuf AST를 받아서 타입 안전한 TypeScript 코드를 생성합니다. Generator는 gRPC 서비스 스텁, 메시지 타입 정의, React Hook 통합 코드를 생성하며, google-protobuf 라이브러리를 사용한 런타임 직렬화/역직렬화를 지원합니다. 생성된 코드는 Promise API와 React Hook API 두 가지 사용 패턴을 모두 지원해야 합니다.

Requirements

Requirement 1

User Story: 개발자로서, .proto 파일에서 정의한 서비스를 TypeScript에서 타입 안전하게 사용할 수 있도록, Generator가 gRPC 서비스 스텁 코드를 생성해야 합니다.

Acceptance Criteria

  1. WHEN Parser AST에 서비스 정의가 있으면 THEN Generator는 해당 서비스의 TypeScript 클래스를 생성해야 합니다
  2. WHEN 서비스 메서드가 정의되면 THEN Generator는 Promise 기반의 메서드를 가진 스텁 클래스를 생성해야 합니다
  3. WHEN 생성된 스텁이 사용되면 THEN 모든 메서드 호출이 타입 안전해야 합니다

Requirement 2

User Story: 개발자로서, .proto 파일의 메시지 타입을 TypeScript에서 사용할 수 있도록, Generator가 메시지 타입 정의와 직렬화 코드를 생성해야 합니다.

Acceptance Criteria

  1. WHEN Parser AST에 메시지 정의가 있으면 THEN Generator는 TypeScript 인터페이스와 클래스를 생성해야 합니다
  2. WHEN 메시지에 다양한 필드 타입이 있으면 THEN Generator는 scalar, repeated, oneof, map 필드를 모두 지원해야 합니다
  3. WHEN 중첩된 메시지나 enum이 있으면 THEN Generator는 네임스페이스를 유지하여 타입을 생성해야 합니다
  4. WHEN 생성된 메시지 클래스가 사용되면 THEN google-protobuf를 사용한 직렬화/역직렬화가 동작해야 합니다

Requirement 3

User Story: React 개발자로서, gRPC 서비스를 React Hook으로 사용할 수 있도록, Generator가 React Hook 통합 코드를 생성해야 합니다.

Acceptance Criteria

  1. WHEN 서비스 정의가 파싱되면 THEN Generator는 React Hook 스텁 클래스를 추가로 생성해야 합니다
  2. WHEN Hook 스텁이 사용되면 THEN 각 서비스 메서드에 대응하는 use[MethodName] Hook을 제공해야 합니다
  3. WHEN React Hook이 호출되면 THEN Suspense와 Error Boundary와 호환되어야 합니다
  4. WHEN Hook이 데이터를 반환하면 THEN 타입 안전한 응답 객체를 제공해야 합니다

Requirement 4

User Story: 빌드 시스템 통합 개발자로서, Generator가 다양한 환경에서 안정적으로 동작하도록, 코드 생성 과정이 최적화되고 에러 처리가 완벽해야 합니다.

Acceptance Criteria

  1. WHEN AST 입력에 오류가 있으면 THEN Generator는 명확한 에러 메시지와 함께 실패해야 합니다
  2. WHEN 대용량 proto 파일이 처리되면 THEN Generator는 합리적인 시간 내에 코드를 생성해야 합니다
  3. WHEN 생성된 코드가 컴파일되면 THEN TypeScript 컴파일러 오류가 발생하지 않아야 합니다
  4. WHEN 메모리 사용량이 많은 경우에도 THEN Generator는 안정적으로 동작해야 합니다

Requirement 5

User Story: 라이브러리 사용자로서, 다양한 Protobuf 기능과 gRPC 패턴을 활용할 수 있도록, Generator가 고급 기능들을 지원해야 합니다.

Acceptance Criteria

  1. WHEN 스트리밍 RPC가 정의되면 THEN Generator는 클라이언트/서버/양방향 스트리밍을 지원하는 코드를 생성해야 합니다
  2. WHEN 커스텀 옵션이 정의되면 THEN Generator는 옵션 정보를 메타데이터로 포함해야 합니다
  3. WHEN import된 proto 파일이 있으면 THEN Generator는 의존성을 올바르게 해결하고 타입을 생성해야 합니다
  4. WHEN 패키지 네임스페이스가 있으면 THEN Generator는 TypeScript 네임스페이스나 모듈을 적절히 생성해야 합니다

Requirement 6

User Story: 개발팀으로서, Generator의 품질을 보장하기 위해, 포괄적인 테스트 커버리지와 코드 품질 검증이 제공되어야 합니다.

Acceptance Criteria

  1. WHEN Generator 코드가 작성되면 THEN 단위 테스트 커버리지가 90% 이상이어야 합니다
  2. WHEN 생성된 코드가 테스트되면 THEN 실제 gRPC 서버와의 통신이 검증되어야 합니다
  3. WHEN 다양한 proto 패턴이 테스트되면 THEN 모든 주요 Protobuf 기능이 올바르게 생성되어야 합니다
  4. WHEN API 문서가 생성되면 THEN Generator의 모든 공개 메서드와 생성 규칙이 문서화되어야 합니다

Requirement 7

User Story: 성능에 민감한 애플리케이션 개발자로서, 생성된 코드가 최적화되어 있도록, Generator가 효율적인 코드를 생성해야 합니다.

Acceptance Criteria

  1. WHEN 코드가 생성되면 THEN 불필요한 코드나 중복 코드가 포함되지 않아야 합니다
  2. WHEN 런타임에 직렬화가 수행되면 THEN google-protobuf의 최적화된 메서드를 사용해야 합니다
  3. WHEN 번들 크기가 측정되면 THEN 생성된 코드는 최소한의 크기를 유지해야 합니다
  4. WHEN Tree-shaking이 적용되면 THEN 사용하지 않는 코드는 제거되어야 합니다

Implementation Plan

  • 1. Set up generator package structure in yarn workspace

    • Create packages/generator directory with src, tests, and templates folders
    • Set up packages/generator/package.json with dependencies (handlebars, typescript, etc.)
    • Configure rollup build system for generator package
    • Add generator package to root workspace configuration
    • Requirements: 4.3, 6.4
  • 2. Implement core Generator interface and infrastructure

    • Create main Generator class with generateCode method
    • Implement GeneratorOptions interface for configuration
    • Create GeneratedCode data model for output structure
    • Set up basic error handling with GenerationError types
    • Requirements: 1.1, 4.1
  • 3. Create template engine with Handlebars integration

    • Implement TemplateEngine class for processing Handlebars templates
    • Set up template loading and caching system
    • Create helper functions for common template operations
    • Add template validation and error reporting
    • Requirements: 4.3, 6.4
  • 4. Implement type mapping utilities

    • Create TypeMapper class for Proto to TypeScript type conversion
    • Map scalar types (string, int32, bool, etc.) to TypeScript types
    • Handle repeated fields, optional fields, and oneof fields
    • Implement complex type mapping for messages and enums
    • Requirements: 2.2, 2.3
  • 5. Create basic service stub generator

    • Implement ServiceGenerator class with generateStub method
    • Create service template for Promise API stub classes
    • Generate TypeScript class with constructor and method signatures
    • Add basic method implementation for unary RPC calls
    • Requirements: 1.1, 1.2, 1.3
  • 6. Implement message type generation

    • Create MessageGenerator class for TypeScript interface generation
    • Generate TypeScript interfaces from message definitions
    • Handle nested messages and maintain proper namespace structure
    • Create message templates for interface generation
    • Requirements: 2.1, 2.3
  • 7. Add google-protobuf serialization code generation

    • Implement serialization code generation in MessageGenerator
    • Create encode/decode methods using google-protobuf Writer/Reader
    • Handle different field types in serialization (scalar, repeated, oneof)
    • Generate namespace-based serialization utilities
    • Requirements: 2.4, 7.2
  • 8. Create React Hook generator infrastructure

    • Implement ReactHookGenerator class for Hook API generation
    • Create React Hook stub class templates
    • Generate use[MethodName] hooks for each service method
    • Add proper TypeScript typing for hook return values
    • Requirements: 3.1, 3.2, 3.4
  • 9. Implement Suspense-compatible React Hooks

    • Add Suspense integration to generated React hooks
    • Implement promise throwing mechanism for Suspense
    • Create error handling compatible with Error Boundary
    • Generate proper hook state management code
    • Requirements: 3.3, 3.4
  • 10. Add import and dependency management

    • Create ImportManager class for managing import statements
    • Generate proper imports for google-protobuf and grpc-web
    • Handle cross-file type references and imports
    • Resolve package namespace imports correctly
    • Requirements: 5.3, 5.4
  • 11. Implement streaming RPC support

    • Extend ServiceGenerator to handle streaming methods
    • Create templates for client streaming, server streaming, and bidirectional streaming
    • Generate proper Observable/Stream-based APIs for streaming
    • Add streaming-specific error handling and cancellation
    • Requirements: 5.1
  • 12. Add custom options and metadata support

    • Parse and include custom options from proto definitions
    • Generate metadata objects with option information
    • Support method-level and service-level options
    • Create extensible option processing system
    • Requirements: 5.2
  • 13. Create comprehensive unit tests for generators

    • Write tests for ServiceGenerator with various RPC patterns
    • Test MessageGenerator with different field types and nesting
    • Add tests for ReactHookGenerator and Suspense integration
    • Test template engine with various template scenarios
    • Requirements: 6.1, 6.3
  • 14. Implement integration tests with real proto files

    • Create test fixtures with complex proto definitions
    • Test end-to-end code generation from AST to working TypeScript
    • Verify generated code compiles without TypeScript errors
    • Test runtime behavior of generated stubs with mock gRPC server
    • Requirements: 6.2, 6.3
  • 15. Add code optimization and tree-shaking support

    • Implement dead code elimination in generated output
    • Optimize import statements to reduce bundle size
    • Add conditional generation based on usage patterns
    • Create minified output options for production builds
    • Requirements: 7.1, 7.3, 7.4
  • 16. Implement performance optimization and benchmarking

    • Add performance monitoring for large proto file generation
    • Implement memory-efficient code generation for large schemas
    • Create benchmark tests for generation speed and memory usage
    • Optimize template processing and type resolution performance
    • Requirements: 4.2, 4.4, 7.2
  • 17. Create API documentation and usage examples

    • Generate TypeDoc documentation for all public Generator APIs
    • Create examples showing different generation patterns and options
    • Document template customization and extension points
    • Add troubleshooting guide for common generation issues
    • Requirements: 6.4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment