Skip to content

Commit 21c5cc6

Browse files
committed
enum support
1 parent 8aeebc4 commit 21c5cc6

File tree

3 files changed

+54
-102
lines changed

3 files changed

+54
-102
lines changed

protographic/examples/field-ordering-stability-demo.ts

Lines changed: 0 additions & 98 deletions
This file was deleted.

protographic/src/operation-to-proto.ts

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,14 @@ import {
1212
visitWithTypeInfo,
1313
getNamedType,
1414
isInputObjectType,
15+
isEnumType,
1516
GraphQLInputObjectType,
17+
GraphQLEnumType,
1618
FragmentDefinitionNode,
1719
} from 'graphql';
1820
import { createFieldNumberManager } from './operations/field-numbering.js';
1921
import { buildMessageFromSelectionSet } from './operations/message-builder.js';
20-
import { buildRequestMessage, buildInputObjectMessage } from './operations/request-builder.js';
22+
import { buildRequestMessage, buildInputObjectMessage, buildEnumType } from './operations/request-builder.js';
2123
import { rootToProtoText } from './operations/proto-text-generator.js';
2224
import {
2325
createRequestMessageName,
@@ -99,8 +101,9 @@ class OperationsToProtoVisitor {
99101
// Proto AST root
100102
private readonly root: protobuf.Root;
101103

102-
// For tracking / avoiding duplicate messages
104+
// For tracking / avoiding duplicate messages and enums
103105
private createdMessages = new Set<string>();
106+
private createdEnums = new Set<string>();
104107

105108
// Lock manager for field number stability
106109
private readonly lockManager: ProtoLockManager;
@@ -211,6 +214,7 @@ class OperationsToProtoVisitor {
211214
fieldNumberManager: this.fieldNumberManager,
212215
fragments: this.fragments,
213216
schema: this.schema,
217+
createdEnums: this.createdEnums,
214218
},
215219
);
216220

@@ -249,7 +253,7 @@ class OperationsToProtoVisitor {
249253
}
250254

251255
/**
252-
* Process input object types referenced in a type node
256+
* Process input object types and enums referenced in a type node
253257
*/
254258
private processInputObjectTypes(typeNode: any): void {
255259
// Handle NonNullType and ListType wrappers
@@ -273,19 +277,39 @@ class OperationsToProtoVisitor {
273277
this.root.add(inputMessage);
274278
this.createdMessages.add(typeName);
275279

276-
// Recursively process nested input objects
280+
// Recursively process nested input objects and enums
277281
const fields = (type as GraphQLInputObjectType).getFields();
278282
for (const field of Object.values(fields)) {
279283
const fieldType = getNamedType(field.type);
280284
if (isInputObjectType(fieldType)) {
281285
this.processInputObjectTypes({ kind: 'NamedType', name: { value: fieldType.name } });
286+
} else if (isEnumType(fieldType)) {
287+
this.processEnumType(fieldType as GraphQLEnumType);
282288
}
283289
}
284290
}
291+
} else if (type && isEnumType(type)) {
292+
// Create enum type if not already created
293+
this.processEnumType(type as GraphQLEnumType);
285294
}
286295
}
287296
}
288297

298+
/**
299+
* Process and add an enum type to the proto root
300+
*/
301+
private processEnumType(enumType: GraphQLEnumType): void {
302+
const typeName = enumType.name;
303+
304+
if (!this.createdEnums.has(typeName)) {
305+
const protoEnum = buildEnumType(enumType, {
306+
includeComments: this.includeComments,
307+
});
308+
this.root.add(protoEnum);
309+
this.createdEnums.add(typeName);
310+
}
311+
}
312+
289313
/**
290314
* Helper: Get root operation type
291315
*/

protographic/src/operations/message-builder.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,20 @@ import {
77
GraphQLSchema,
88
TypeInfo,
99
isObjectType,
10+
isEnumType,
1011
getNamedType,
1112
InlineFragmentNode,
1213
FragmentDefinitionNode,
1314
GraphQLOutputType,
15+
GraphQLEnumType,
1416
FragmentSpreadNode,
1517
isInterfaceType,
1618
isUnionType,
1719
} from 'graphql';
1820
import { mapGraphQLTypeToProto, ProtoTypeInfo } from './type-mapper.js';
1921
import { FieldNumberManager } from './field-numbering.js';
2022
import { graphqlFieldToProtoField } from '../naming-conventions.js';
23+
import { buildEnumType } from './request-builder.js';
2124
import { upperFirst, camelCase } from 'lodash-es';
2225

2326
/**
@@ -34,6 +37,8 @@ export interface MessageBuilderOptions {
3437
fragments?: Map<string, FragmentDefinitionNode>;
3538
/** Schema for type lookups */
3639
schema?: GraphQLSchema;
40+
/** Set to track created enums (to avoid duplicates) */
41+
createdEnums?: Set<string>;
3742
}
3843

3944
/**
@@ -224,6 +229,27 @@ function processFieldSelection(
224229
}
225230
} else {
226231
// Scalar or enum field
232+
const namedType = getNamedType(fieldType);
233+
234+
// If this is an enum type, ensure it's added to the root
235+
if (isEnumType(namedType) && options?.root) {
236+
const enumTypeName = namedType.name;
237+
const createdEnums = options.createdEnums || new Set<string>();
238+
239+
if (!createdEnums.has(enumTypeName)) {
240+
const protoEnum = buildEnumType(namedType as GraphQLEnumType, {
241+
includeComments: options.includeComments,
242+
});
243+
options.root.add(protoEnum);
244+
createdEnums.add(enumTypeName);
245+
246+
// Update the set in options if it was provided
247+
if (options.createdEnums) {
248+
options.createdEnums.add(enumTypeName);
249+
}
250+
}
251+
}
252+
227253
const protoTypeInfo = mapGraphQLTypeToProto(fieldType);
228254

229255
// Get field number - check if already assigned from reconciliation

0 commit comments

Comments
 (0)