Utilities for processing GraphQL selection sets and converting them to TypeScript object types, with support for fragments, nested selections, and complex field resolution. These tools enable the transformation of GraphQL queries and fragments into strongly-typed TypeScript interfaces.
Core class for converting GraphQL selection sets into TypeScript object type definitions with full support for fragments, nested selections, and type resolution.
/**
* Converts GraphQL selection sets to TypeScript object types
*/
class SelectionSetToObject {
/**
* Creates a new processor instance for nested selection processing
* @param parentType - GraphQL object type containing the selection
* @param selectionSet - GraphQL selection set node to process
* @returns New SelectionSetToObject instance for the nested context
*/
createNext(parentType: GraphQLObjectType, selectionSet: SelectionSetNode): SelectionSetToObject;
/**
* Transforms a selection set into a TypeScript type definition
* @param typeName - Name for the generated TypeScript type
* @returns Generated TypeScript type definition string
*/
transformSelectionSet(typeName: string): string;
/**
* Transforms fragment selection sets into TypeScript type definitions
* @returns Generated TypeScript type definitions for fragment spreads
*/
transformFragmentSelectionSetToTypes(): string;
/**
* Gets the selection set as a TypeScript object type
* @returns TypeScript object type string
*/
getSelectionSetType(): string;
/**
* Gets primitive fields from the selection set
* @returns Object with primitive field information
*/
getPrimitiveFields(): { [fieldName: string]: PrimitiveField };
/**
* Gets linked fields (object/interface fields) from the selection set
* @returns Object with linked field information
*/
getLinkedFields(): { [fieldName: string]: LinkField };
/**
* Gets fragment spreads from the selection set
* @returns Array of fragment spread information
*/
getFragmentSpreads(): Array<{
fragmentName: string;
typeName: string;
onType: string;
}>;
}
/**
* Information about a primitive field in a selection set
*/
interface PrimitiveField {
/** Field name */
fieldName: string;
/** TypeScript type for the field */
type: string;
/** Whether the field is optional */
isOptional: boolean;
/** Field alias if used */
alias?: string;
/** Field arguments if any */
arguments?: { [argName: string]: any };
}
/**
* Aliased primitive fields grouped by field name
*/
interface PrimitiveAliasedFields {
[fieldName: string]: PrimitiveField[];
}
/**
* Information about a linked (object/interface) field in a selection set
*/
interface LinkField {
/** Field name */
fieldName: string;
/** GraphQL type for the field */
type: GraphQLOutputType;
/** Nested selection set processor */
selectionSet: SelectionSetToObject;
/** Whether the field is optional */
isOptional: boolean;
/** Field alias if used */
alias?: string;
/** Field arguments if any */
arguments?: { [argName: string]: any };
}
/**
* Simple name and type pair
*/
interface NameAndType {
name: string;
type: string;
}Usage Examples:
import { SelectionSetToObject } from "@graphql-codegen/visitor-plugin-common";
import { GraphQLObjectType, SelectionSetNode } from "graphql";
// Process a user query selection set
const userType = schema.getType('User') as GraphQLObjectType;
const selectionSet: SelectionSetNode = {
kind: 'SelectionSet',
selections: [
{ kind: 'Field', name: { kind: 'Name', value: 'id' } },
{ kind: 'Field', name: { kind: 'Name', value: 'name' } },
{ kind: 'Field', name: { kind: 'Name', value: 'email' } }
]
};
const processor = new SelectionSetToObject(
schema,
userType,
selectionSet,
config
);
// Generate TypeScript type
const userQueryType = processor.transformSelectionSet('UserQuery');
// Result: interface UserQuery { id: string; name: string; email?: string; }Class for converting GraphQL operation variables into TypeScript object type definitions with proper type mapping and null handling.
/**
* Converts GraphQL operation variables to TypeScript object types
*/
class OperationVariablesToObject {
/**
* Transforms variable definitions into a TypeScript type definition
* @param variableDefinitions - Array of GraphQL variable definition nodes
* @returns Generated TypeScript type definition for variables
*/
transform(variableDefinitions: ReadonlyArray<VariableDefinitionNode>): string;
/**
* Wraps a TypeScript type with appropriate modifiers (optional, array, non-null)
* @param typeToUse - Base TypeScript type string
* @param typeNode - GraphQL type node with modifiers
* @returns Type string with applied modifiers
*/
wrapAstTypeWithModifiers(typeToUse: string, typeNode: TypeNode): string;
/**
* Gets the TypeScript type for a GraphQL type node
* @param typeNode - GraphQL type node
* @returns TypeScript type string
*/
getTypeToUse(typeNode: TypeNode): string;
/**
* Gets variable definition string for a single variable
* @param variable - GraphQL variable definition node
* @returns TypeScript property definition string
*/
getVariableDefinition(variable: VariableDefinitionNode): string;
/**
* Checks if variables object should be optional (all variables are optional)
* @param variableDefinitions - Array of variable definition nodes
* @returns True if variables object can be optional
*/
shouldMakeVariablesOptional(variableDefinitions: ReadonlyArray<VariableDefinitionNode>): boolean;
}Usage Examples:
import { OperationVariablesToObject } from "@graphql-codegen/visitor-plugin-common";
import { VariableDefinitionNode } from "graphql";
// Process operation variables
const variables: VariableDefinitionNode[] = [
{
kind: 'VariableDefinition',
variable: { kind: 'Variable', name: { kind: 'Name', value: 'id' } },
type: { kind: 'NonNullType', type: { kind: 'NamedType', name: { kind: 'Name', value: 'ID' } } }
},
{
kind: 'VariableDefinition',
variable: { kind: 'Variable', name: { kind: 'Name', value: 'filter' } },
type: { kind: 'NamedType', name: { kind: 'Name', value: 'UserFilter' } }
}
];
const processor = new OperationVariablesToObject(schema, config);
const variablesType = processor.transform(variables);
// Result: { id: string; filter?: UserFilter }Abstract base class for implementing custom selection set processing logic with extensible patterns for different code generation needs.
/**
* Abstract base class for processing GraphQL selection sets
*/
abstract class BaseSelectionSetProcessor {
/**
* Processes a selection set and returns processing results
* @param selectionSet - GraphQL selection set node
* @param parentType - Parent GraphQL type containing the selection
* @returns Processing results object
*/
abstract process(selectionSet: SelectionSetNode, parentType: GraphQLObjectType): ProcessResult;
/**
* Processes primitive fields in a selection set
* @param fields - Array of GraphQL field nodes
* @param parentType - Parent GraphQL type
* @returns Processed primitive fields
*/
protected processPrimitiveFields(
fields: FieldNode[],
parentType: GraphQLObjectType
): { [fieldName: string]: PrimitiveField };
/**
* Processes linked fields (object/interface fields) in a selection set
* @param fields - Array of GraphQL field nodes
* @param parentType - Parent GraphQL type
* @returns Processed linked fields
*/
protected processLinkedFields(
fields: FieldNode[],
parentType: GraphQLObjectType
): { [fieldName: string]: LinkField };
/**
* Processes fragment spreads in a selection set
* @param fragments - Array of fragment spread nodes
* @param parentType - Parent GraphQL type
* @returns Processed fragment spread information
*/
protected processFragmentSpreads(
fragments: FragmentSpreadNode[],
parentType: GraphQLObjectType
): Array<{ fragmentName: string; typeName: string; onType: string }>;
/**
* Processes inline fragments in a selection set
* @param inlineFragments - Array of inline fragment nodes
* @param parentType - Parent GraphQL type
* @returns Processed inline fragment information
*/
protected processInlineFragments(
inlineFragments: InlineFragmentNode[],
parentType: GraphQLObjectType
): Array<{ typeName: string; selectionSet: SelectionSetNode }>;
}
/**
* Result of selection set processing
*/
interface ProcessResult {
/** Processed primitive fields */
primitiveFields: { [fieldName: string]: PrimitiveField };
/** Processed linked fields */
linkedFields: { [fieldName: string]: LinkField };
/** Processed fragment spreads */
fragmentSpreads: Array<{ fragmentName: string; typeName: string; onType: string }>;
/** Processed inline fragments */
inlineFragments: Array<{ typeName: string; selectionSet: SelectionSetNode }>;
/** Generated TypeScript type definition */
typeDefinition: string;
}Specialized selection set processor that pre-resolves types for better performance and more precise type generation.
/**
* Selection set processor that pre-resolves types for optimal performance
*/
class PreResolveTypesProcessor extends BaseSelectionSetProcessor {
/**
* Processes selection set with type pre-resolution
* @param selectionSet - GraphQL selection set node
* @param parentType - Parent GraphQL type
* @returns Processing results with pre-resolved types
*/
process(selectionSet: SelectionSetNode, parentType: GraphQLObjectType): ProcessResult;
/**
* Pre-resolves types for better code generation performance
* @param type - GraphQL type to resolve
* @returns Resolved type information
*/
preResolveType(type: GraphQLOutputType): {
type: string;
isOptional: boolean;
isArray: boolean;
};
/**
* Optimizes selection set by removing redundant selections
* @param selectionSet - GraphQL selection set to optimize
* @returns Optimized selection set
*/
optimizeSelectionSet(selectionSet: SelectionSetNode): SelectionSetNode;
}Usage Examples:
// Extend BaseSelectionSetProcessor for custom processing
class CustomSelectionSetProcessor extends BaseSelectionSetProcessor {
process(selectionSet: SelectionSetNode, parentType: GraphQLObjectType): ProcessResult {
const primitiveFields = this.processPrimitiveFields(
selectionSet.selections.filter(s => s.kind === 'Field') as FieldNode[],
parentType
);
const linkedFields = this.processLinkedFields(
selectionSet.selections.filter(s => s.kind === 'Field') as FieldNode[],
parentType
);
return {
primitiveFields,
linkedFields,
fragmentSpreads: [],
inlineFragments: [],
typeDefinition: this.buildTypeDefinition(primitiveFields, linkedFields)
};
}
private buildTypeDefinition(primitiveFields: any, linkedFields: any): string {
// Custom type definition building logic
return '{ /* custom type */ }';
}
}
// Use with custom processor
const customProcessor = new CustomSelectionSetProcessor(schema, config);
const result = customProcessor.process(selectionSet, parentType);