Skip to content

Conversation

@grounzero
Copy link
Owner

@grounzero grounzero commented Apr 24, 2025

Add Schema-Aware Type Inference to GraphQL Fragment Generator

Overview

This PR enhances the GraphQL fragment generator with schema awareness, allowing it to accurately predict field types based on GraphQL schema definitions. This addresses a significant limitation in the current implementation, where type information had to be manually specified or was inferred with limited accuracy.

Changes Summary

  1. Added Schema Models: Created comprehensive models for GraphQL schema elements
  2. Implemented Schema Parser: Added a parser to extract type information from GraphQL schema definitions
  3. Enhanced Fragment Generator: Modified to use schema information for accurate type inference
  4. Added Configuration Options: New options for schema files and custom scalar mappings
  5. Improved Error Handling: Added diagnostics for schema-related issues
  6. Added Tests: Comprehensive tests for schema parsing and type inference
  7. Added Documentation: Examples and guidance for using schema-aware features

Detailed Changes

1. Schema Models (GraphQLSourceGen/Models/GraphQLSchemaModels.cs)

Added a new file with models for GraphQL schema elements:

  • GraphQLSchema: Container for all schema elements with helper methods
  • GraphQLTypeDefinition: For object types with fields and interface implementations
  • GraphQLInterfaceDefinition: For interface types with field definitions
  • GraphQLUnionDefinition: For union types with possible types
  • GraphQLEnumDefinition: For enum types with values
  • GraphQLScalarDefinition: For custom scalar types
  • GraphQLInputDefinition: For input object types
  • GraphQLFieldDefinition: For field definitions with type information
  • GraphQLInputValueDefinition: For input values (arguments and input fields)

These models provide a comprehensive representation of GraphQL schema elements, enabling accurate type inference.

2. Schema Parser (GraphQLSourceGen/Parsing/GraphQLSchemaParser.cs)

Implemented a parser that extracts type information from GraphQL schema definitions:

  • Parses type definitions with interface implementations
  • Handles field definitions with arguments and type information
  • Supports interface, union, enum, input, and scalar type definitions
  • Processes directives, including @deprecated
  • Includes robust error handling and recovery

The parser is designed to handle complex schema features while providing meaningful error messages for invalid syntax.

3. Enhanced Fragment Generator (GraphQLSourceGen/GraphQLFragmentGenerator.cs)

Modified the fragment generator to use schema information:

  • Added schema parsing and loading from specified files
  • Implemented EnhanceFragmentsWithSchema method to apply type information
  • Updated property generation to use schema-derived types
  • Added support for custom scalar mappings
  • Improved handling of deprecated fields

These changes enable the generator to produce more accurate C# types based on the GraphQL schema.

4. Configuration Options (GraphQLSourceGen/Configuration/GraphQLSourceGenOptions.cs)

Added new configuration options:

  • UseSchemaForTypeInference: Enable/disable schema-based type inference
  • SchemaFilePaths: Paths to schema definition files
  • CustomScalarMappings: Custom mappings for scalar types
  • ValidateNonNullableFields: Generate validation for non-nullable fields
  • IncludeFieldDescriptions: Include field descriptions from schema

These options provide flexibility in how schema information is used for type generation.

5. Diagnostics (GraphQLSourceGen/Diagnostics/DiagnosticDescriptors.cs)

Added new diagnostics for schema-related issues:

  • SchemaFileNotFound: When a specified schema file is not found
  • InvalidSchemaDefinition: For invalid schema syntax
  • TypeNotFoundInSchema: When a fragment references a type not in the schema
  • FieldNotFoundInType: When a field is not found in a type
  • InvalidFragmentOnInterfaceOrUnion: For fragments on interfaces/unions without __typename

These diagnostics help developers identify and fix issues in their GraphQL schemas.

6. Parser Enhancements (GraphQLSourceGen/Parsing/GraphQLParser.cs)

Modified the existing parser:

  • Made Tokenize method public for reuse in schema parser
  • Added support for comment tokens
  • Improved directive handling for better deprecation support
  • Enhanced type parsing for more accurate type information

These changes ensure compatibility between fragment and schema parsing.

7. Build Properties (GraphQLSourceGen/build/GraphQLSourceGen.props)

Updated default configuration:

  • Added default values for new schema-related options
  • Included default scalar mappings for common types
  • Added comments explaining the new options

8. Sample Implementation (GraphQLSourceGen.Samples/SchemaAwareExample.cs)

Added a sample implementation demonstrating schema-aware fragment generation:

  • Shows how to load and parse a GraphQL schema
  • Demonstrates enhancing fragments with schema information
  • Illustrates the benefits of schema-aware type inference

9. Tests

Added comprehensive tests:

  • GraphQLSchemaParserTests.cs: Tests for schema parsing
  • GraphQLSchemaAwareGeneratorTests.cs: Tests for schema-aware type inference
  • ComplexSchemaTests.cs: Tests for complex schema features

Rationale

The primary motivation for these changes is to improve type safety and developer experience:

  1. Type Safety: By using schema information, the generator can produce more accurate C# types, reducing runtime errors.
  2. Developer Experience: Developers no longer need to manually specify types in fragments, as they are inferred from the schema.
  3. Maintainability: Changes to the schema are automatically reflected in generated code, reducing maintenance overhead.
  4. Compatibility: The implementation supports complex GraphQL features like interfaces, unions, and custom scalars.

Edge Cases and Considerations

  1. Schema Evolution: When schemas evolve, generated code may change. Consider versioning strategies for schema changes.
  2. Custom Scalars: Default mappings are provided, but custom scalars may require specific mappings.
  3. Circular References: The implementation handles circular references in schemas, but deep nesting may impact performance.
  4. Large Schemas: For very large schemas, consider performance implications and potential optimizations.
  5. Schema Validation: The implementation validates fragments against the schema, but does not validate the schema itself.

Breaking Changes

None. The implementation is backward compatible with existing code. Schema awareness is opt-in through configuration options.

Future Improvements

  1. Schema validation for fragments
  2. Support for schema directives beyond @deprecated
  3. Handling of schema extensions
  4. Support for schema introspection
  5. Integration with GraphQL clients

Testing

The implementation includes comprehensive tests covering:

  • Schema parsing for various schema elements
  • Type inference for different field types
  • Handling of deprecated fields
  • Complex nested structures
  • Custom scalar mappings

All tests pass, ensuring the implementation is robust and reliable.

@grounzero grounzero merged commit 8ed6c92 into main May 15, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants