@wundergraph/protographic 0.15.6 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/dist/src/abstract-selection-rewriter.d.ts +265 -0
  2. package/dist/src/abstract-selection-rewriter.js +585 -0
  3. package/dist/src/abstract-selection-rewriter.js.map +1 -0
  4. package/dist/src/index.d.ts +2 -0
  5. package/dist/src/index.js +4 -2
  6. package/dist/src/index.js.map +1 -1
  7. package/dist/src/naming-conventions.d.ts +59 -0
  8. package/dist/src/naming-conventions.js +82 -7
  9. package/dist/src/naming-conventions.js.map +1 -1
  10. package/dist/src/operation-to-proto.js +9 -6
  11. package/dist/src/operation-to-proto.js.map +1 -1
  12. package/dist/src/operations/field-numbering.js +6 -3
  13. package/dist/src/operations/field-numbering.js.map +1 -1
  14. package/dist/src/operations/message-builder.js +38 -23
  15. package/dist/src/operations/message-builder.js.map +1 -1
  16. package/dist/src/operations/proto-field-options.js.map +1 -1
  17. package/dist/src/operations/proto-text-generator.js +16 -27
  18. package/dist/src/operations/proto-text-generator.js.map +1 -1
  19. package/dist/src/operations/request-builder.js +5 -3
  20. package/dist/src/operations/request-builder.js.map +1 -1
  21. package/dist/src/operations/type-mapper.js +3 -22
  22. package/dist/src/operations/type-mapper.js.map +1 -1
  23. package/dist/src/proto-lock.js +19 -19
  24. package/dist/src/proto-lock.js.map +1 -1
  25. package/dist/src/proto-utils.d.ts +74 -0
  26. package/dist/src/proto-utils.js +286 -0
  27. package/dist/src/proto-utils.js.map +1 -0
  28. package/dist/src/required-fields-visitor.d.ts +230 -0
  29. package/dist/src/required-fields-visitor.js +513 -0
  30. package/dist/src/required-fields-visitor.js.map +1 -0
  31. package/dist/src/sdl-to-mapping-visitor.d.ts +9 -1
  32. package/dist/src/sdl-to-mapping-visitor.js +72 -12
  33. package/dist/src/sdl-to-mapping-visitor.js.map +1 -1
  34. package/dist/src/sdl-to-proto-visitor.d.ts +20 -66
  35. package/dist/src/sdl-to-proto-visitor.js +270 -390
  36. package/dist/src/sdl-to-proto-visitor.js.map +1 -1
  37. package/dist/src/sdl-validation-visitor.d.ts +2 -0
  38. package/dist/src/sdl-validation-visitor.js +85 -29
  39. package/dist/src/sdl-validation-visitor.js.map +1 -1
  40. package/dist/src/selection-set-validation-visitor.d.ts +112 -0
  41. package/dist/src/selection-set-validation-visitor.js +199 -0
  42. package/dist/src/selection-set-validation-visitor.js.map +1 -0
  43. package/dist/src/string-constants.d.ts +4 -0
  44. package/dist/src/string-constants.js +4 -0
  45. package/dist/src/string-constants.js.map +1 -1
  46. package/dist/src/types.d.ts +102 -0
  47. package/dist/src/types.js +37 -1
  48. package/dist/src/types.js.map +1 -1
  49. package/dist/tsconfig.tsbuildinfo +1 -1
  50. package/package.json +9 -5
@@ -0,0 +1,286 @@
1
+ import { isListType, isNonNullType, isScalarType, isEnumType, getNamedType, } from 'graphql';
2
+ import { isUnionMessageDefinition, SCALAR_TYPE_MAP, SCALAR_WRAPPER_TYPE_MAP, } from './types.js';
3
+ import { unwrapNonNullType, isNestedListType, calculateNestingLevel } from './operations/list-type-utils.js';
4
+ import { graphqlFieldToProtoField } from './naming-conventions.js';
5
+ const SPACE_INDENT = ' '; // 2 spaces
6
+ const LINE_COMMENT_PREFIX = '// ';
7
+ const BLOCK_COMMENT_START = '/*';
8
+ const BLOCK_COMMENT_END = '*/';
9
+ /**
10
+ * Builds a message definition from a ProtoMessage object
11
+ * @param message - The ProtoMessage object
12
+ * @returns The message definition
13
+ */
14
+ export function buildProtoMessage(includeComments, message) {
15
+ return buildProtoMessageWithIndent(includeComments, message, 0, new Set());
16
+ }
17
+ /**
18
+ * Builds a message definition from a ProtoMessage object with an indent level
19
+ * @param includeComments - Whether to include comments
20
+ * @param message - The ProtoMessage object
21
+ * @param indent - The indent level
22
+ * @returns The message lines
23
+ */
24
+ function buildProtoMessageWithIndent(includeComments, message, indent, seenTypes) {
25
+ const messageLines = formatComment(includeComments, message.description, indent);
26
+ if (seenTypes.has(message.messageName)) {
27
+ throw new Error(`Duplicate nested message name: ${message.messageName}`);
28
+ }
29
+ seenTypes.add(message.messageName);
30
+ messageLines.push(indentContent(indent, `message ${message.messageName} {`));
31
+ // Build nested messages first - use a new Set for this level since
32
+ // protobuf allows the same message name at different nesting levels
33
+ if (message.nestedMessages && message.nestedMessages.length > 0) {
34
+ const nestedSeenTypes = new Set();
35
+ for (const nestedMessage of message.nestedMessages) {
36
+ messageLines.push(...buildProtoMessageWithIndent(includeComments, nestedMessage, indent + 1, nestedSeenTypes));
37
+ }
38
+ }
39
+ if (message.reservedNumbers && message.reservedNumbers.length > 0) {
40
+ messageLines.push(indentContent(indent + 1, `reserved ${message.reservedNumbers};`));
41
+ }
42
+ const compositeTypeFields = message.fields.filter((f) => f.compositeType);
43
+ for (const compositeTypeField of compositeTypeFields) {
44
+ messageLines.push(...buildCompositeTypeMessage(includeComments, compositeTypeField.compositeType, indent + 1, seenTypes));
45
+ }
46
+ for (const field of message.fields) {
47
+ if (field.description) {
48
+ messageLines.push(...formatComment(includeComments, field.description, indent + 1));
49
+ }
50
+ const repeated = field.isRepeated ? 'repeated ' : '';
51
+ messageLines.push(indentContent(indent + 1, `${repeated}${field.typeName} ${field.fieldName} = ${field.fieldNumber};`));
52
+ }
53
+ messageLines.push(indentContent(indent, '}'), '');
54
+ return messageLines;
55
+ }
56
+ /**
57
+ * Builds a composite type message
58
+ * @param includeComments - Whether to include comments
59
+ * @param compositeType - The composite type definition
60
+ * @param indent - The indent level
61
+ * @returns The message lines
62
+ * @example
63
+ * ```proto
64
+ * // A union type uses `value`
65
+ * message Animal {
66
+ * oneof value {
67
+ * Cat cat = 1;
68
+ * Dog dog = 2;
69
+ * }
70
+ * }
71
+ *
72
+ * // An interface type uses `instance`
73
+ * message Animal {
74
+ * oneof instance {
75
+ * Cat cat = 1;
76
+ * Dog dog = 2;
77
+ * }
78
+ * }
79
+ * ```
80
+ */
81
+ function buildCompositeTypeMessage(includeComments, compositeType, indent, seenTypes) {
82
+ if (seenTypes.has(compositeType.typeName)) {
83
+ return [];
84
+ }
85
+ seenTypes.add(compositeType.typeName);
86
+ const lines = [];
87
+ if (includeComments && compositeType.description) {
88
+ lines.push(...formatComment(includeComments, compositeType.description, indent));
89
+ }
90
+ let oneOfName = '';
91
+ let compositeTypes = [];
92
+ if (isUnionMessageDefinition(compositeType)) {
93
+ oneOfName = 'value';
94
+ compositeTypes = compositeType.memberTypes;
95
+ }
96
+ else {
97
+ oneOfName = 'instance';
98
+ compositeTypes = compositeType.implementingTypes;
99
+ }
100
+ // Create a sorted copy to ensure deterministic field numbers without mutating the input.
101
+ compositeTypes = [...compositeTypes].sort((a, b) => a.localeCompare(b));
102
+ lines.push(indentContent(indent, `message ${compositeType.typeName} {`), indentContent(indent + 1, `oneof ${oneOfName} {`));
103
+ for (const [index, compositeType] of compositeTypes.entries()) {
104
+ lines.push(indentContent(indent + 2, `${compositeType} ${graphqlFieldToProtoField(compositeType)} = ${index + 1};`));
105
+ }
106
+ lines.push(indentContent(indent + 1, '}'));
107
+ lines.push(indentContent(indent, '}'));
108
+ return lines;
109
+ }
110
+ /**
111
+ * Convert a GraphQL description to Protocol Buffer comment
112
+ * @param description - The GraphQL description text
113
+ * @param indentLevel - The level of indentation for the comment (in number of 2-space blocks)
114
+ * @returns Array of comment lines with proper indentation
115
+ */
116
+ export function formatComment(includeComments, description, indentLevel = 0) {
117
+ if (!includeComments || !description) {
118
+ return [];
119
+ }
120
+ // Sanitize description to prevent breaking block comments.
121
+ // Replace "/*" and "*/" with safe alternatives so they don't interfere
122
+ // with the BLOCK_COMMENT_START/BLOCK_COMMENT_END markers.
123
+ const sanitized = description.replace(/\/\*/g, '/ *').replace(/\*\//g, '* /');
124
+ // Use 2-space indentation consistently
125
+ const indent = SPACE_INDENT.repeat(indentLevel);
126
+ const lines = sanitized.trim().split('\n');
127
+ return lines.length === 1
128
+ ? [`${indent}${LINE_COMMENT_PREFIX}${lines[0]}`]
129
+ : [
130
+ `${indent}${BLOCK_COMMENT_START}`,
131
+ ...lines.map((line) => `${indent} * ${line}`),
132
+ `${indent} ${BLOCK_COMMENT_END}`,
133
+ ];
134
+ }
135
+ export function renderRPCMethod(includeComments, rpcMethod) {
136
+ const lines = [];
137
+ if (includeComments && rpcMethod.description) {
138
+ lines.push(...formatComment(includeComments, rpcMethod.description, 1));
139
+ }
140
+ lines.push(indentContent(1, `rpc ${rpcMethod.name}(${rpcMethod.request}) returns (${rpcMethod.response}) {}`));
141
+ return lines;
142
+ }
143
+ /**
144
+ * Map GraphQL type to Protocol Buffer type
145
+ *
146
+ * Determines the appropriate Protocol Buffer type for a given GraphQL type,
147
+ * including the use of wrapper types for nullable scalar fields to distinguish
148
+ * between unset fields and zero values.
149
+ *
150
+ * @param graphqlType - The GraphQL type to convert
151
+ * @param ignoreWrapperTypes - If true, do not use wrapper types for nullable scalar fields
152
+ * @returns The corresponding Protocol Buffer type name
153
+ */
154
+ export function getProtoTypeFromGraphQL(includeComments, graphqlType, ignoreWrapperTypes = false) {
155
+ // Nullable lists need to be handled first, otherwise they will be treated as scalar types
156
+ if (isListType(graphqlType) || (isNonNullType(graphqlType) && isListType(graphqlType.ofType))) {
157
+ return handleListType(includeComments, graphqlType);
158
+ }
159
+ // For nullable scalar types, use wrapper types
160
+ if (isScalarType(graphqlType)) {
161
+ if (ignoreWrapperTypes) {
162
+ return { typeName: SCALAR_TYPE_MAP[graphqlType.name] || 'string', isRepeated: false, isWrapper: false };
163
+ }
164
+ return {
165
+ typeName: SCALAR_WRAPPER_TYPE_MAP[graphqlType.name] || 'google.protobuf.StringValue',
166
+ isRepeated: false,
167
+ isWrapper: true,
168
+ };
169
+ }
170
+ if (isEnumType(graphqlType)) {
171
+ return { typeName: graphqlType.name, isRepeated: false, isWrapper: false };
172
+ }
173
+ if (isNonNullType(graphqlType)) {
174
+ // For non-null scalar types, use the base type
175
+ if (isScalarType(graphqlType.ofType)) {
176
+ return { typeName: SCALAR_TYPE_MAP[graphqlType.ofType.name] || 'string', isRepeated: false, isWrapper: false };
177
+ }
178
+ return getProtoTypeFromGraphQL(includeComments, graphqlType.ofType);
179
+ }
180
+ // Named types (object, interface, union, input)
181
+ const namedType = graphqlType;
182
+ if (namedType && typeof namedType.name === 'string') {
183
+ return { typeName: namedType.name, isRepeated: false, isWrapper: false };
184
+ }
185
+ return { typeName: 'string', isRepeated: false, isWrapper: false }; // Default fallback
186
+ }
187
+ /**
188
+ * Converts GraphQL list types to appropriate Protocol Buffer representations.
189
+ *
190
+ * For non-nullable, single-level lists (e.g., [String!]!), generates simple repeated fields.
191
+ * For nullable lists (e.g., [String]) or nested lists (e.g., [[String]]), creates wrapper
192
+ * messages to properly handle nullability in proto3.
193
+ *
194
+ * Examples:
195
+ * - [String!]! → repeated string field_name = 1;
196
+ * - [String] → ListOfString field_name = 1; (with wrapper message)
197
+ * - [[String!]!]! → ListOfListOfString field_name = 1; (with nested wrapper messages)
198
+ * - [[String]] → ListOfListOfString field_name = 1; (with nested wrapper messages)
199
+ *
200
+ * @param graphqlType - The GraphQL list type to convert
201
+ * @returns ProtoType object containing the type name and whether it should be repeated
202
+ */
203
+ export function handleListType(includeComments, graphqlType) {
204
+ const listType = unwrapNonNullType(graphqlType);
205
+ const isNullableList = !isNonNullType(graphqlType);
206
+ const isNested = isNestedListType(listType);
207
+ // Simple non-nullable lists can use repeated fields directly
208
+ if (!isNullableList && !isNested) {
209
+ return { ...getProtoTypeFromGraphQL(includeComments, getNamedType(listType), true), isRepeated: true };
210
+ }
211
+ // Nullable or nested lists need wrapper messages
212
+ const baseType = getNamedType(listType);
213
+ const nestingLevel = calculateNestingLevel(listType);
214
+ // For nested lists, always use full nesting level to preserve inner list nullability
215
+ // For single-level nullable lists, use nesting level 1
216
+ const wrapperNestingLevel = isNested ? nestingLevel : 1;
217
+ // Generate all required wrapper messages
218
+ const wrapperName = listNameByNestingLevel(wrapperNestingLevel, baseType);
219
+ // For nested lists, never use repeated at field level to preserve nullability
220
+ return {
221
+ typeName: wrapperName,
222
+ isWrapper: false,
223
+ isRepeated: false,
224
+ listWrapper: { baseType, nestingLevel: wrapperNestingLevel },
225
+ };
226
+ }
227
+ export function listNameByNestingLevel(nestingLevel, baseType) {
228
+ return `${'ListOf'.repeat(nestingLevel)}${baseType.name}`;
229
+ }
230
+ /**
231
+ * Creates wrapper messages for nullable or nested GraphQL lists.
232
+ *
233
+ * Generates Protocol Buffer message definitions to handle list nullability and nesting.
234
+ * The wrapper messages are stored and later included in the final proto output.
235
+ *
236
+ * For level 1: Creates simple wrapper like:
237
+ * message ListOfString {
238
+ * repeated string items = 1;
239
+ * }
240
+ *
241
+ * For level > 1: Creates nested wrapper structures like:
242
+ * message ListOfListOfString {
243
+ * message List {
244
+ * repeated ListOfString items = 1;
245
+ * }
246
+ * List list = 1;
247
+ * }
248
+ *
249
+ * @param includeComments - Whether to include descriptive comments in the output
250
+ * @param level - The nesting level (1 for simple wrapper, >1 for nested structures)
251
+ * @param baseType - The GraphQL base type being wrapped (e.g., String, User, etc.)
252
+ * @returns The generated wrapper message definition as a proto message string.
253
+ * Constructs a `wrapperName` (e.g., "ListOfString", "ListOfListOfUser") and
254
+ * uses `buildWrapperMessage(includeComments, wrapperName, level, baseType)`
255
+ * to render the full message text.
256
+ */
257
+ export function createNestedListWrapper(includeComments, level, baseType) {
258
+ const wrapperName = `${'ListOf'.repeat(level)}${baseType.name}`;
259
+ return buildWrapperMessage(includeComments, wrapperName, level, baseType).join('\n');
260
+ }
261
+ /**
262
+ * Builds the message lines for a wrapper message
263
+ */
264
+ function buildWrapperMessage(includeComments, wrapperName, level, baseType) {
265
+ const lines = [];
266
+ // Add comment if enabled
267
+ if (includeComments) {
268
+ lines.push(...formatComment(includeComments, `Wrapper message for a list of ${baseType.name}.`, 0));
269
+ }
270
+ lines.push(`message ${wrapperName} {`);
271
+ let innerWrapperName = '';
272
+ innerWrapperName =
273
+ level > 1
274
+ ? `${'ListOf'.repeat(level - 1)}${baseType.name}`
275
+ : getProtoTypeFromGraphQL(includeComments, baseType, true).typeName;
276
+ lines.push(indentContent(1, `message List {`), indentContent(2, `repeated ${innerWrapperName} items = 1;`), indentContent(1, `}`), indentContent(1, `List list = 1;`), `}`);
277
+ return lines;
278
+ }
279
+ /**
280
+ * Indents the content by the given indent level
281
+ * @param indentLevel - The indent level
282
+ * @param content - The content to indent
283
+ * @returns The indented content
284
+ */
285
+ const indentContent = (indentLevel, content) => SPACE_INDENT.repeat(indentLevel) + content;
286
+ //# sourceMappingURL=proto-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proto-utils.js","sourceRoot":"","sources":["../../src/proto-utils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,230 @@
1
+ import { GraphQLField, GraphQLObjectType, GraphQLSchema } from 'graphql';
2
+ import { FieldMapping } from '@wundergraph/cosmo-connect/dist/node/v1/node_pb';
3
+ import { ProtoMessage, RPCMethod } from './types.js';
4
+ /**
5
+ * A record mapping key directive strings to their corresponding RequiredFieldMapping.
6
+ * Each entity can have multiple @key directives, and each key needs its own RPC mapping.
7
+ */
8
+ type RequiredFieldMappings = Record<string, RequiredFieldMapping>;
9
+ /**
10
+ * Represents the mapping configuration for a single @requires field.
11
+ * This mapping is keyed by the @key directive fields string.
12
+ */
13
+ export type RequiredFieldMapping = {
14
+ /** The RPC method configuration for resolving this required field */
15
+ rpc?: RPCMethod;
16
+ /** The field mapping between GraphQL and proto field names */
17
+ requiredFieldMapping?: FieldMapping;
18
+ };
19
+ /**
20
+ * Generates protobuf messages and RPC methods for @requires directive field sets.
21
+ *
22
+ * This visitor processes the field set defined in a @requires directive and generates:
23
+ * - RPC method definitions for fetching required fields
24
+ * - Request/response message definitions
25
+ * - Field mappings between GraphQL and protobuf
26
+ *
27
+ * The visitor handles each @key directive on the entity separately, creating
28
+ * distinct RPC methods for each key since required fields may need to be
29
+ * fetched using different entity keys.
30
+ *
31
+ * @example
32
+ * ```typescript
33
+ * const visitor = new RequiredFieldsVisitor(
34
+ * schema,
35
+ * ProductType,
36
+ * weightField,
37
+ * 'dimensions { width height }'
38
+ * );
39
+ * visitor.visit();
40
+ *
41
+ * const messages = visitor.getMessageDefinitions();
42
+ * const rpcs = visitor.getRPCMethods();
43
+ * const mappings = visitor.getMapping();
44
+ * ```
45
+ */
46
+ export declare class RequiredFieldsVisitor {
47
+ private readonly schema;
48
+ private readonly objectType;
49
+ private readonly requiredField;
50
+ private readonly visitor;
51
+ private readonly fieldSetDoc;
52
+ private ancestors;
53
+ private currentType;
54
+ private keyDirectives;
55
+ private currentKeyFieldsString;
56
+ /** Collected RPC methods for the required fields */
57
+ private rpcMethods;
58
+ /** All generated protobuf message definitions */
59
+ private messageDefinitions;
60
+ /** The current required field message being built */
61
+ private requiredFieldMessage;
62
+ /** The current message context during traversal */
63
+ private current;
64
+ /** Stack for tracking nested message contexts */
65
+ private stack;
66
+ private currentInlineFragment?;
67
+ private inlineFragmentStack;
68
+ /** Mappings keyed by @key directive fields string */
69
+ private mapping;
70
+ /**
71
+ * Creates a new RequiredFieldsVisitor.
72
+ *
73
+ * @param schema - The GraphQL schema containing type definitions
74
+ * @param objectType - The entity type that has the @requires directive
75
+ * @param requiredField - The field with the @requires directive
76
+ * @param fieldSet - The field set string from the @requires directive (e.g., "dimensions { width height }")
77
+ * @param options - Optional configuration options
78
+ * @throws Error if the object type is not an entity (has no @key directive)
79
+ */
80
+ constructor(schema: GraphQLSchema, objectType: GraphQLObjectType, requiredField: GraphQLField<any, any, any>, fieldSet: string);
81
+ /**
82
+ * Executes the visitor, processing the field set for each @key directive.
83
+ * Creates separate RPC methods and mappings for each entity key.
84
+ */
85
+ visit(): void;
86
+ /**
87
+ * Normalizes the parsed field set operation by rewriting abstract selections.
88
+ * This ensures consistent handling of interface and union type selections.
89
+ */
90
+ private normalizeSelectionSet;
91
+ /**
92
+ * Returns all generated protobuf message definitions.
93
+ *
94
+ * @returns Array of ProtoMessage definitions for request, response, and nested messages
95
+ */
96
+ getMessageDefinitions(): ProtoMessage[];
97
+ /**
98
+ * Returns the generated RPC method definitions.
99
+ *
100
+ * @returns Array of RPCMethod definitions for fetching required fields
101
+ */
102
+ getRPCMethods(): RPCMethod[];
103
+ /**
104
+ * Returns the field mappings keyed by @key directive fields string.
105
+ *
106
+ * @returns Record mapping key strings to their RequiredFieldMapping configurations
107
+ */
108
+ getMapping(): RequiredFieldMappings;
109
+ /**
110
+ * Resolves all @key directives from the object type.
111
+ * Each key directive will result in a separate RPC method.
112
+ *
113
+ * @throws Error if the object type has no @key directives
114
+ */
115
+ private resolveKeyDirectives;
116
+ /**
117
+ * Creates the AST visitor configuration for traversing the field set document.
118
+ *
119
+ * @returns An ASTVisitor with handlers for Document, Field, InlineFragment, and SelectionSet nodes
120
+ */
121
+ private createASTVisitor;
122
+ /**
123
+ * Handles leaving the document node.
124
+ * Finalizes the required field message and generates type field mappings.
125
+ */
126
+ private onLeaveDocument;
127
+ /**
128
+ * Handles entering the document node.
129
+ * Creates the RPC method definition and all request/response message structures
130
+ * for fetching the required fields.
131
+ *
132
+ * @param node - The document node being entered
133
+ */
134
+ private onEnterDocument;
135
+ /**
136
+ * Handles entering a field node during traversal.
137
+ * Adds the field to the current proto message with appropriate type mapping.
138
+ *
139
+ * @param ctx - The visit context containing the field node and its ancestors
140
+ * @throws Error if the field definition is not found on the current type
141
+ */
142
+ private onEnterField;
143
+ /**
144
+ * Handles entering an inline fragment node.
145
+ * Pushes the current inline fragment onto the stack for nested fragment handling.
146
+ *
147
+ * @param ctx - The visit context containing the inline fragment node
148
+ */
149
+ private onEnterInlineFragment;
150
+ /**
151
+ * Handles leaving an inline fragment node.
152
+ * Records union member types when processing union type fragments.
153
+ *
154
+ * @param ctx - The visit context containing the inline fragment node
155
+ */
156
+ private onLeaveInlineFragment;
157
+ /**
158
+ * Handles entering a selection set node.
159
+ * Creates a new nested proto message for object type selections and updates
160
+ * the current type context for proper field resolution.
161
+ *
162
+ * @param ctx - The visit context containing the selection set node and its parent
163
+ */
164
+ private onEnterSelectionSet;
165
+ /**
166
+ * Handles leaving a selection set node.
167
+ * Restores the previous type and message context when ascending the tree,
168
+ * but only if onEnterSelectionSet actually pushed state.
169
+ *
170
+ * @param ctx - The visit context containing the selection set node
171
+ */
172
+ private onLeaveSelectionSet;
173
+ /**
174
+ * Handles composite types (interfaces and unions) by setting up the
175
+ * appropriate composite type metadata on the current message.
176
+ *
177
+ * @param fieldDefinition - The field definition with a composite type
178
+ */
179
+ private handleCompositeType;
180
+ /**
181
+ * Type guard to check if a node is a FieldNode.
182
+ *
183
+ * @param node - The AST node or array of nodes to check
184
+ * @returns True if the node is a FieldNode
185
+ */
186
+ private isFieldNode;
187
+ /**
188
+ * Type guard to check if a node is an InlineFragmentNode.
189
+ *
190
+ * @param node - The AST node or array of nodes to check
191
+ * @returns True if the node is an InlineFragmentNode
192
+ */
193
+ private isInlineFragmentNode;
194
+ /**
195
+ * Finds the GraphQL object type for a field by looking up the field's return type.
196
+ *
197
+ * @param fieldName - The name of the field to look up
198
+ * @returns The GraphQL object type if the field returns an object type, undefined otherwise
199
+ */
200
+ private findObjectTypeForField;
201
+ /**
202
+ * Retrieves the field definition for a field name from the current type.
203
+ *
204
+ * @param fieldName - The name of the field to look up
205
+ * @returns The GraphQL field definition, or undefined if not found
206
+ */
207
+ private fieldDefinition;
208
+ /**
209
+ * Finds a GraphQL object type by name from the schema's type map.
210
+ *
211
+ * @param typeName - The name of the type to find
212
+ * @returns The GraphQL object type if found and is an object type, undefined otherwise
213
+ */
214
+ private findObjectType;
215
+ /**
216
+ * Extracts the fields string from a @key directive's fields argument.
217
+ *
218
+ * @param directive - The @key directive node
219
+ * @returns The fields string value, or empty string if not found
220
+ */
221
+ private getKeyFieldsString;
222
+ /**
223
+ * Checks if a GraphQL type is a composite type (interface or union).
224
+ *
225
+ * @param type - The GraphQL type to check
226
+ * @returns True if the type is an interface or union type
227
+ */
228
+ private isCompositeType;
229
+ }
230
+ export {};