Next Steps for ChainGraph Code Generator
Last Updated: 2025-10-15 Current Status: Phase 2 Complete - Multi-schema generation working Next Phase: Advanced union handling and type alias support
✅ What's Been Completed
Phase 1: Foundation
- [x] TypeScript AST parsing
- [x] Type mapping
- [x] Dependency discovery
- [x] Basic test coverage
Phase 2: Multi-Schema Generation
- [x] Separate @ObjectSchema for each nested type
- [x] Schema references (@PortObject, @PortArray)
- [x] Full type preservation
- [x] Topological sorting
- [x] Self-reference handling
- [x] Built-in type filtering
🎯 Phase 3: Advanced Type Handling (Next)
1. Union Type Support (High Priority)
Problem: Complex unions currently map to @PortAny
Examples:
// Gemini SDK
type ContentUnion = Content | PartUnion[] | PartUnion
type PartUnion = Part | string
// Currently generates:
@PortAny({ title: 'System Instruction' })
systemInstruction?: any // ❌ Lost type informationSolution: Add union flattening logic
// Option 1: Pick primary type
type ContentUnion = Content | PartUnion[] | PartUnion
→ Use Content (the object type)
→ @PortObject({ schema: Content })
// Option 2: Generate union wrapper
@ObjectSchema({ type: 'ContentUnion' })
class ContentUnion {
@PortObject({ schema: Content })
content?: Content
@PortArray({ itemConfig: { schema: Part } })
parts?: Part[]
@PortString()
text?: string
}Implementation:
- File:
src/core/TypeMapper.ts - Method:
mapUnion()- Add logic to detect union patterns - Estimated time: 2-3 hours
2. Type Alias Generation (Medium Priority)
Problem: Type aliases are discovered but not generated
Example:
// Gemini SDK
export type ContentUnion = Content | PartUnion[] | PartUnion
// Currently: Skipped
// Future: Generate wrapper or select primary typeImplementation:
- File:
src/core/TemplateEngine.ts - Add:
generateTypeAlias()method - Estimated time: 2 hours
3. Native Enum Support (Medium Priority)
Problem: Gemini uses string literal unions, not TypeScript enums
Current:
// Gemini SDK uses:
type HarmCategory = 'HARM_CATEGORY_HATE_SPEECH' | 'HARM_CATEGORY_HARASSMENT'
// Generates:
@PortEnum({
options: [
{ id: 'HARM_CATEGORY_HATE_SPEECH', type: 'string', ... },
]
})
category?: stringFuture (when SDK has real enums):
// If SDK had:
enum HarmCategory {
HARM_CATEGORY_HATE_SPEECH = "...",
}
// Generate:
export enum HarmCategory { /* ... */ }
@PortEnumFromNative(HarmCategory, { /* ... */ })
category?: HarmCategoryImplementation:
- Already supported! Just needs SDKs to use real enums
- No changes needed
4. Custom Type Mappers API (Low Priority)
Goal: Allow users to override type mapping for specific types
Example:
const generator = new CodeGenerator({
library: '@google/genai',
typeName: 'GenerateContentConfig',
customTypeMappers: {
'ContentUnion': (type) => ({
config: {
type: 'object',
schema: Content, // Always use Content
},
metadata: {
typeRef: 'Content',
},
}),
},
})Implementation:
- Already has basic support in TypeMapper constructor
- Needs documentation and examples
- Estimated time: 1 hour
🔧 Improvements & Polish
1. CLI Enhancements
Add options:
--max-depth <number> # Control dependency discovery depth (default: 10)
--skip-built-ins # Skip browser/Node types (default: true)
--output-mode <mode> # single-file | multi-file (future)2. Better Error Messages
Current:
Error: Type "Foo" not found in @bar/bazFuture:
Error: Type "Foo" not found in @bar/baz
Suggestions:
- Did you mean "FooBar"? (similar name found)
- Available types: Bar, Baz, FooBar, Qux
- Check type is exported from main .d.ts file3. Performance Optimization
Current: ~10 seconds for 62 types
Optimizations:
- Parallel schema generation
- Caching parsed .d.ts files
- Incremental generation
Target: <5 seconds for 100+ types
📊 Success Metrics
Current State
- ✅ 36/36 tests passing
- ✅ 62 schemas generated from GenerateContentConfig
- ✅ 2,435 lines of output
- ✅ Zero TypeScript errors
- ✅ Full type preservation
Phase 3 Goals
- [ ] Handle 90% of union types correctly
- [ ] Generate type aliases
- [ ] <5 second generation time
- [ ] 50+ tests covering edge cases
- [ ] Documentation with real-world examples
🎓 For the Next Developer
If implementing union handling:
Study the patterns:
bash# Find all union usages in Gemini SDK grep "type.*=.*|" node_modules/@google/genai/dist/genai.d.tsUnderstand current behavior:
- Read:
src/core/TypeMapper.tslines 159-231 (mapUnion) - See how literal unions become enums
- See how complex unions become @PortAny
- Read:
Add union flattening:
- Detect pattern:
A | B | Cwhere A is primary object type - Use A as the schema type
- Document that B and C are ignored
- Detect pattern:
Test with real SDK:
typescript// Test that ContentUnion generates correctly const code = await generator.generateMultiSchema() expect(code).toContain('@PortObject({ schema: Content })')
If implementing type aliases:
Extend TemplateEngine:
- Add
generateTypeAlias()method - Decision: Generate as wrapper class or select primary type?
- Add
Update CodeGenerator:
- Handle
metadata.kind === 'type-alias' - Currently skipped in generateMultiSchema()
- Handle
Add tests:
- Create
type-alias-generation.test.ts - Test simple aliases:
type Foo = Bar - Test union aliases:
type Foo = A | B
- Create
🔗 Resources
Documentation
- README.md - Project overview
- CHECKPOINT.md - Current state
- ARCHITECTURE.md - System design
- IMPLEMENTATION_PLAN_V2.md - Detailed implementation guide
Key Files
- src/core/CodeGenerator.ts:104 -
generateMultiSchema()method - src/core/TypeMapper.ts:159 -
mapUnion()method - src/core/TemplateEngine.ts:495 -
generateObjectSchema()method
Tests
- src/tests/multi-schema-generation.test.ts - Multi-schema tests
- src/tests/gemini-dependencies.test.ts - Dependency discovery
Ready for Phase 3! Start with union type handling for maximum impact.