UNPKG

29.6 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.SelectionSetToObject = void 0;
4const tslib_1 = require("tslib");
5const graphql_1 = require("graphql");
6const utils_js_1 = require("./utils.js");
7const plugin_helpers_1 = require("@graphql-codegen/plugin-helpers");
8const auto_bind_1 = tslib_1.__importDefault(require("auto-bind"));
9const utils_1 = require("@graphql-tools/utils");
10const crypto_1 = require("crypto");
11function isMetadataFieldName(name) {
12 return ['__schema', '__type'].includes(name);
13}
14const metadataFieldMap = {
15 __schema: graphql_1.SchemaMetaFieldDef,
16 __type: graphql_1.TypeMetaFieldDef,
17};
18class SelectionSetToObject {
19 constructor(_processor, _scalars, _schema, _convertName, _getFragmentSuffix, _loadedFragments, _config, _parentSchemaType, _selectionSet) {
20 this._processor = _processor;
21 this._scalars = _scalars;
22 this._schema = _schema;
23 this._convertName = _convertName;
24 this._getFragmentSuffix = _getFragmentSuffix;
25 this._loadedFragments = _loadedFragments;
26 this._config = _config;
27 this._parentSchemaType = _parentSchemaType;
28 this._selectionSet = _selectionSet;
29 this._primitiveFields = [];
30 this._primitiveAliasedFields = [];
31 this._linksFields = [];
32 this._queriedForTypename = false;
33 (0, auto_bind_1.default)(this);
34 }
35 createNext(parentSchemaType, selectionSet) {
36 return new SelectionSetToObject(this._processor, this._scalars, this._schema, this._convertName.bind(this), this._getFragmentSuffix.bind(this), this._loadedFragments, this._config, parentSchemaType, selectionSet);
37 }
38 /**
39 * traverse the inline fragment nodes recursively for collecting the selectionSets on each type
40 */
41 _collectInlineFragments(parentType, nodes, types) {
42 if ((0, graphql_1.isListType)(parentType) || (0, graphql_1.isNonNullType)(parentType)) {
43 return this._collectInlineFragments(parentType.ofType, nodes, types);
44 }
45 if ((0, graphql_1.isObjectType)(parentType)) {
46 for (const node of nodes) {
47 const typeOnSchema = node.typeCondition ? this._schema.getType(node.typeCondition.name.value) : parentType;
48 const { fields, inlines, spreads } = (0, utils_js_1.separateSelectionSet)(node.selectionSet.selections);
49 const spreadsUsage = this.buildFragmentSpreadsUsage(spreads);
50 const directives = node.directives || undefined;
51 if ((0, graphql_1.isObjectType)(typeOnSchema)) {
52 this._appendToTypeMap(types, typeOnSchema.name, fields);
53 this._appendToTypeMap(types, typeOnSchema.name, spreadsUsage[typeOnSchema.name]);
54 this._appendToTypeMap(types, typeOnSchema.name, directives);
55 this._collectInlineFragments(typeOnSchema, inlines, types);
56 }
57 else if ((0, graphql_1.isInterfaceType)(typeOnSchema) && parentType.getInterfaces().includes(typeOnSchema)) {
58 this._appendToTypeMap(types, parentType.name, fields);
59 this._appendToTypeMap(types, parentType.name, spreadsUsage[parentType.name]);
60 this._collectInlineFragments(typeOnSchema, inlines, types);
61 }
62 }
63 }
64 else if ((0, graphql_1.isInterfaceType)(parentType)) {
65 const possibleTypes = (0, utils_js_1.getPossibleTypes)(this._schema, parentType);
66 for (const node of nodes) {
67 const schemaType = node.typeCondition ? this._schema.getType(node.typeCondition.name.value) : parentType;
68 const { fields, inlines, spreads } = (0, utils_js_1.separateSelectionSet)(node.selectionSet.selections);
69 const spreadsUsage = this.buildFragmentSpreadsUsage(spreads);
70 if ((0, graphql_1.isObjectType)(schemaType) && possibleTypes.find(possibleType => possibleType.name === schemaType.name)) {
71 this._appendToTypeMap(types, schemaType.name, fields);
72 this._appendToTypeMap(types, schemaType.name, spreadsUsage[schemaType.name]);
73 this._collectInlineFragments(schemaType, inlines, types);
74 }
75 else if ((0, graphql_1.isInterfaceType)(schemaType) && schemaType.name === parentType.name) {
76 for (const possibleType of possibleTypes) {
77 this._appendToTypeMap(types, possibleType.name, fields);
78 this._appendToTypeMap(types, possibleType.name, spreadsUsage[possibleType.name]);
79 this._collectInlineFragments(schemaType, inlines, types);
80 }
81 }
82 else {
83 // it must be an interface type that is spread on an interface field
84 for (const possibleType of possibleTypes) {
85 if (!node.typeCondition) {
86 throw new Error('Invalid state. Expected type condition for interface spread on a interface field.');
87 }
88 const fragmentSpreadType = this._schema.getType(node.typeCondition.name.value);
89 // the field should only be added to the valid selections
90 // in case the possible type actually implements the given interface
91 if ((0, graphql_1.isTypeSubTypeOf)(this._schema, possibleType, fragmentSpreadType)) {
92 this._appendToTypeMap(types, possibleType.name, fields);
93 this._appendToTypeMap(types, possibleType.name, spreadsUsage[possibleType.name]);
94 }
95 }
96 }
97 }
98 }
99 else if ((0, graphql_1.isUnionType)(parentType)) {
100 const possibleTypes = parentType.getTypes();
101 for (const node of nodes) {
102 const schemaType = node.typeCondition ? this._schema.getType(node.typeCondition.name.value) : parentType;
103 const { fields, inlines, spreads } = (0, utils_js_1.separateSelectionSet)(node.selectionSet.selections);
104 const spreadsUsage = this.buildFragmentSpreadsUsage(spreads);
105 if ((0, graphql_1.isObjectType)(schemaType) && possibleTypes.find(possibleType => possibleType.name === schemaType.name)) {
106 this._appendToTypeMap(types, schemaType.name, fields);
107 this._appendToTypeMap(types, schemaType.name, spreadsUsage[schemaType.name]);
108 this._collectInlineFragments(schemaType, inlines, types);
109 }
110 else if ((0, graphql_1.isInterfaceType)(schemaType)) {
111 const possibleInterfaceTypes = (0, utils_js_1.getPossibleTypes)(this._schema, schemaType);
112 for (const possibleType of possibleTypes) {
113 if (possibleInterfaceTypes.find(possibleInterfaceType => possibleInterfaceType.name === possibleType.name)) {
114 this._appendToTypeMap(types, possibleType.name, fields);
115 this._appendToTypeMap(types, possibleType.name, spreadsUsage[possibleType.name]);
116 this._collectInlineFragments(schemaType, inlines, types);
117 }
118 }
119 }
120 else {
121 for (const possibleType of possibleTypes) {
122 this._appendToTypeMap(types, possibleType.name, fields);
123 this._appendToTypeMap(types, possibleType.name, spreadsUsage[possibleType.name]);
124 }
125 }
126 }
127 }
128 }
129 _createInlineFragmentForFieldNodes(parentType, fieldNodes) {
130 return {
131 kind: graphql_1.Kind.INLINE_FRAGMENT,
132 typeCondition: {
133 kind: graphql_1.Kind.NAMED_TYPE,
134 name: {
135 kind: graphql_1.Kind.NAME,
136 value: parentType.name,
137 },
138 },
139 directives: [],
140 selectionSet: {
141 kind: graphql_1.Kind.SELECTION_SET,
142 selections: fieldNodes,
143 },
144 };
145 }
146 buildFragmentSpreadsUsage(spreads) {
147 const selectionNodesByTypeName = {};
148 for (const spread of spreads) {
149 const fragmentSpreadObject = this._loadedFragments.find(lf => lf.name === spread.name.value);
150 if (fragmentSpreadObject) {
151 const schemaType = this._schema.getType(fragmentSpreadObject.onType);
152 const possibleTypesForFragment = (0, utils_js_1.getPossibleTypes)(this._schema, schemaType);
153 for (const possibleType of possibleTypesForFragment) {
154 const fragmentSuffix = this._getFragmentSuffix(spread.name.value);
155 const usage = this.buildFragmentTypeName(spread.name.value, fragmentSuffix, possibleTypesForFragment.length === 1 ? null : possibleType.name);
156 if (!selectionNodesByTypeName[possibleType.name]) {
157 selectionNodesByTypeName[possibleType.name] = [];
158 }
159 selectionNodesByTypeName[possibleType.name].push({
160 fragmentName: spread.name.value,
161 typeName: usage,
162 onType: fragmentSpreadObject.onType,
163 selectionNodes: [...fragmentSpreadObject.node.selectionSet.selections],
164 });
165 }
166 }
167 }
168 return selectionNodesByTypeName;
169 }
170 flattenSelectionSet(selections, parentSchemaType) {
171 const selectionNodesByTypeName = new Map();
172 const inlineFragmentSelections = [];
173 const fieldNodes = [];
174 const fragmentSpreads = [];
175 for (const selection of selections) {
176 switch (selection.kind) {
177 case graphql_1.Kind.FIELD:
178 fieldNodes.push(selection);
179 break;
180 case graphql_1.Kind.INLINE_FRAGMENT:
181 inlineFragmentSelections.push(selection);
182 break;
183 case graphql_1.Kind.FRAGMENT_SPREAD:
184 fragmentSpreads.push(selection);
185 break;
186 }
187 }
188 if (fieldNodes.length) {
189 inlineFragmentSelections.push(this._createInlineFragmentForFieldNodes(parentSchemaType !== null && parentSchemaType !== void 0 ? parentSchemaType : this._parentSchemaType, fieldNodes));
190 }
191 this._collectInlineFragments(parentSchemaType !== null && parentSchemaType !== void 0 ? parentSchemaType : this._parentSchemaType, inlineFragmentSelections, selectionNodesByTypeName);
192 const fragmentsUsage = this.buildFragmentSpreadsUsage(fragmentSpreads);
193 for (const [typeName, records] of Object.entries(fragmentsUsage)) {
194 this._appendToTypeMap(selectionNodesByTypeName, typeName, records);
195 }
196 return selectionNodesByTypeName;
197 }
198 _appendToTypeMap(types, typeName, nodes) {
199 if (!types.has(typeName)) {
200 types.set(typeName, []);
201 }
202 if (nodes && nodes.length > 0) {
203 types.get(typeName).push(...nodes);
204 }
205 }
206 /**
207 * mustAddEmptyObject indicates that not all possible types on a union or interface field are covered.
208 */
209 _buildGroupedSelections() {
210 if (!this._selectionSet || !this._selectionSet.selections || this._selectionSet.selections.length === 0) {
211 return { grouped: {}, mustAddEmptyObject: true };
212 }
213 const selectionNodesByTypeName = this.flattenSelectionSet(this._selectionSet.selections);
214 // in case there is not a selection for each type, we need to add a empty type.
215 let mustAddEmptyObject = false;
216 const possibleTypes = (0, utils_js_1.getPossibleTypes)(this._schema, this._parentSchemaType);
217 if (!this._config.mergeFragmentTypes || this._config.inlineFragmentTypes === 'mask') {
218 const grouped = possibleTypes.reduce((prev, type) => {
219 const typeName = type.name;
220 const schemaType = this._schema.getType(typeName);
221 if (!(0, graphql_1.isObjectType)(schemaType)) {
222 throw new TypeError(`Invalid state! Schema type ${typeName} is not a valid GraphQL object!`);
223 }
224 const selectionNodes = selectionNodesByTypeName.get(typeName) || [];
225 if (!prev[typeName]) {
226 prev[typeName] = [];
227 }
228 const { fields } = this.buildSelectionSet(schemaType, selectionNodes);
229 const transformedSet = this.selectionSetStringFromFields(fields);
230 if (transformedSet) {
231 prev[typeName].push(transformedSet);
232 }
233 else {
234 mustAddEmptyObject = true;
235 }
236 return prev;
237 }, {});
238 return { grouped, mustAddEmptyObject };
239 }
240 // Accumulate a map of selected fields to the typenames that
241 // share the exact same selected fields. When we find multiple
242 // typenames with the same set of fields, we can collapse the
243 // generated type to the selected fields and a string literal
244 // union of the typenames.
245 //
246 // E.g. {
247 // __typename: "foo" | "bar";
248 // shared: string;
249 // }
250 const grouped = possibleTypes.reduce((prev, type) => {
251 var _a, _b;
252 const typeName = type.name;
253 const schemaType = this._schema.getType(typeName);
254 if (!(0, graphql_1.isObjectType)(schemaType)) {
255 throw new TypeError(`Invalid state! Schema type ${typeName} is not a valid GraphQL object!`);
256 }
257 const selectionNodes = selectionNodesByTypeName.get(typeName) || [];
258 const { typeInfo, fields } = this.buildSelectionSet(schemaType, selectionNodes);
259 const key = this.selectionSetStringFromFields(fields);
260 prev[key] = {
261 fields,
262 types: [...((_b = (_a = prev[key]) === null || _a === void 0 ? void 0 : _a.types) !== null && _b !== void 0 ? _b : []), typeInfo || { name: '', type: type.name }].filter(Boolean),
263 };
264 return prev;
265 }, {});
266 // For every distinct set of fields, create the corresponding
267 // string literal union of typenames.
268 const compacted = Object.keys(grouped).reduce((acc, key) => {
269 const typeNames = grouped[key].types.map(t => t.type);
270 // Don't create very large string literal unions. TypeScript
271 // will stop comparing some nested union types types when
272 // they contain props with more than some number of string
273 // literal union members (testing with TS 4.5 stops working
274 // at 25 for a naive test case:
275 // https://www.typescriptlang.org/play?ts=4.5.4&ssl=29&ssc=10&pln=29&pc=1#code/C4TwDgpgBAKg9nAMgQwE4HNoF4BQV9QA+UA3ngRQJYB21EqAXDsQEQCMLzULATJ6wGZ+3ACzCWAVnEA2cQHZxADnEBOcWwAM6jl3Z9dbIQbEGpB2QYUHlBtbp5b7O1j30ujLky7Os4wABb0nAC+ODigkFAAQlBYUOT4xGQUVLT0TKzO3G7cHqLiPtwWrFasNqx2mY6ZWXrqeexe3GyF7MXNpc3lzZXZ1dm1ruI8DTxNvGahFEkJKTR0jLMpRNx+gaicy6E4APQ7AALAAM4AtJTo1HCoEDgANhDAUMgMsAgoGNikwQDcdw9QACMXjE4shfmEItAAGI0bCzGbLfDzdIGYbiBrjVrtFidFjdFi9dj9di1Ng5dgNNjjFrqbFsXFsfFsQkOYaDckjYbjNZBHDbPaHU7nS7XP6PZBsF4wuixL6-e6PAGS6KyiXfIA
276 const max_types = 20;
277 for (let i = 0; i < typeNames.length; i += max_types) {
278 const selectedTypes = typeNames.slice(i, i + max_types);
279 const typenameUnion = grouped[key].types[0].name
280 ? this._processor.transformTypenameField(selectedTypes.join(' | '), grouped[key].types[0].name)
281 : [];
282 const transformedSet = this.selectionSetStringFromFields([...typenameUnion, ...grouped[key].fields]);
283 // The keys here will be used to generate intermediary
284 // fragment names. To avoid blowing up the type name on large
285 // unions, calculate a stable hash here instead.
286 //
287 // Also use fragment hashing if skipTypename is true, since we
288 // then don't have a typename for naming the fragment.
289 acc[selectedTypes.length <= 3
290 ? selectedTypes.join('_')
291 : (0, crypto_1.createHash)('sha256')
292 .update(selectedTypes.join() || transformedSet || '')
293 .digest('base64')] = [transformedSet];
294 }
295 return acc;
296 }, {});
297 return { grouped: compacted, mustAddEmptyObject };
298 }
299 selectionSetStringFromFields(fields) {
300 const allStrings = fields.filter((f) => typeof f === 'string');
301 const allObjects = fields
302 .filter((f) => typeof f !== 'string')
303 .map(t => `${t.name}: ${t.type}`);
304 const mergedObjects = allObjects.length ? this._processor.buildFieldsIntoObject(allObjects) : null;
305 const transformedSet = this._processor.buildSelectionSetFromStrings([...allStrings, mergedObjects].filter(Boolean));
306 return transformedSet;
307 }
308 buildSelectionSet(parentSchemaType, selectionNodes) {
309 var _a, _b, _c;
310 const primitiveFields = new Map();
311 const primitiveAliasFields = new Map();
312 const linkFieldSelectionSets = new Map();
313 let requireTypename = false;
314 // usages via fragment typescript type
315 const fragmentsSpreadUsages = [];
316 // ensure we mutate no function params
317 selectionNodes = [...selectionNodes];
318 let inlineFragmentConditional = false;
319 for (const selectionNode of selectionNodes) {
320 if ('kind' in selectionNode) {
321 if (selectionNode.kind === 'Field') {
322 if (!selectionNode.selectionSet) {
323 if (selectionNode.alias) {
324 primitiveAliasFields.set(selectionNode.alias.value, selectionNode);
325 }
326 else if (selectionNode.name.value === '__typename') {
327 requireTypename = true;
328 }
329 else {
330 primitiveFields.set(selectionNode.name.value, selectionNode);
331 }
332 }
333 else {
334 let selectedField = null;
335 const fields = parentSchemaType.getFields();
336 selectedField = fields[selectionNode.name.value];
337 if (isMetadataFieldName(selectionNode.name.value)) {
338 selectedField = metadataFieldMap[selectionNode.name.value];
339 }
340 if (!selectedField) {
341 continue;
342 }
343 const fieldName = (0, utils_js_1.getFieldNodeNameValue)(selectionNode);
344 let linkFieldNode = linkFieldSelectionSets.get(fieldName);
345 if (!linkFieldNode) {
346 linkFieldNode = {
347 selectedFieldType: selectedField.type,
348 field: selectionNode,
349 };
350 }
351 else {
352 linkFieldNode = {
353 ...linkFieldNode,
354 field: {
355 ...linkFieldNode.field,
356 selectionSet: (0, utils_js_1.mergeSelectionSets)(linkFieldNode.field.selectionSet, selectionNode.selectionSet),
357 },
358 };
359 }
360 linkFieldSelectionSets.set(fieldName, linkFieldNode);
361 }
362 }
363 else if (selectionNode.kind === 'Directive') {
364 if (['skip', 'include'].includes((_a = selectionNode === null || selectionNode === void 0 ? void 0 : selectionNode.name) === null || _a === void 0 ? void 0 : _a.value)) {
365 inlineFragmentConditional = true;
366 }
367 }
368 else {
369 throw new TypeError('Unexpected type.');
370 }
371 continue;
372 }
373 if (this._config.inlineFragmentTypes === 'combine' || this._config.inlineFragmentTypes === 'mask') {
374 fragmentsSpreadUsages.push(selectionNode.typeName);
375 continue;
376 }
377 // Handle Fragment Spreads by generating inline types.
378 const fragmentType = this._schema.getType(selectionNode.onType);
379 if (fragmentType == null) {
380 throw new TypeError(`Unexpected error: Type ${selectionNode.onType} does not exist within schema.`);
381 }
382 if (parentSchemaType.name === selectionNode.onType ||
383 parentSchemaType.getInterfaces().find(iinterface => iinterface.name === selectionNode.onType) != null ||
384 ((0, graphql_1.isUnionType)(fragmentType) &&
385 fragmentType.getTypes().find(objectType => objectType.name === parentSchemaType.name))) {
386 // also process fields from fragment that apply for this parentType
387 const flatten = this.flattenSelectionSet(selectionNode.selectionNodes, parentSchemaType);
388 const typeNodes = (_b = flatten.get(parentSchemaType.name)) !== null && _b !== void 0 ? _b : [];
389 selectionNodes.push(...typeNodes);
390 for (const iinterface of parentSchemaType.getInterfaces()) {
391 const typeNodes = (_c = flatten.get(iinterface.name)) !== null && _c !== void 0 ? _c : [];
392 selectionNodes.push(...typeNodes);
393 }
394 }
395 }
396 const linkFields = [];
397 for (const { field, selectedFieldType } of linkFieldSelectionSets.values()) {
398 const realSelectedFieldType = (0, plugin_helpers_1.getBaseType)(selectedFieldType);
399 const selectionSet = this.createNext(realSelectedFieldType, field.selectionSet);
400 const isConditional = (0, utils_js_1.hasConditionalDirectives)(field) || inlineFragmentConditional;
401 linkFields.push({
402 alias: field.alias ? this._processor.config.formatNamedField(field.alias.value, selectedFieldType) : undefined,
403 name: this._processor.config.formatNamedField(field.name.value, selectedFieldType, isConditional),
404 type: realSelectedFieldType.name,
405 selectionSet: this._processor.config.wrapTypeWithModifiers(selectionSet.transformSelectionSet().split(`\n`).join(`\n `), selectedFieldType),
406 });
407 }
408 const typeInfoField = this.buildTypeNameField(parentSchemaType, this._config.nonOptionalTypename, this._config.addTypename, requireTypename, this._config.skipTypeNameForRoot);
409 const transformed = [
410 // Only add the typename field if we're not merging fragment
411 // types. If we are merging, we need to wait until we know all
412 // the involved typenames.
413 ...(typeInfoField && (!this._config.mergeFragmentTypes || this._config.inlineFragmentTypes === 'mask')
414 ? this._processor.transformTypenameField(typeInfoField.type, typeInfoField.name)
415 : []),
416 ...this._processor.transformPrimitiveFields(parentSchemaType, Array.from(primitiveFields.values()).map(field => ({
417 isConditional: (0, utils_js_1.hasConditionalDirectives)(field),
418 fieldName: field.name.value,
419 }))),
420 ...this._processor.transformAliasesPrimitiveFields(parentSchemaType, Array.from(primitiveAliasFields.values()).map(field => ({
421 alias: field.alias.value,
422 fieldName: field.name.value,
423 }))),
424 ...this._processor.transformLinkFields(linkFields),
425 ].filter(Boolean);
426 const allStrings = transformed.filter(t => typeof t === 'string');
427 const allObjectsMerged = transformed
428 .filter(t => typeof t !== 'string')
429 .map((t) => `${t.name}: ${t.type}`);
430 let mergedObjectsAsString = null;
431 if (allObjectsMerged.length > 0) {
432 mergedObjectsAsString = this._processor.buildFieldsIntoObject(allObjectsMerged);
433 }
434 const fields = [...allStrings, mergedObjectsAsString].filter(Boolean);
435 if (fragmentsSpreadUsages.length) {
436 if (this._config.inlineFragmentTypes === 'combine') {
437 fields.push(...fragmentsSpreadUsages);
438 }
439 else if (this._config.inlineFragmentTypes === 'mask') {
440 fields.push(`{ ' $fragmentRefs'?: { ${fragmentsSpreadUsages.map(name => `'${name}': ${name}`).join(`;`)} } }`);
441 }
442 }
443 return { typeInfo: typeInfoField, fields };
444 }
445 buildTypeNameField(type, nonOptionalTypename = this._config.nonOptionalTypename, addTypename = this._config.addTypename, queriedForTypename = this._queriedForTypename, skipTypeNameForRoot = this._config.skipTypeNameForRoot) {
446 const rootTypes = (0, utils_1.getRootTypes)(this._schema);
447 if (rootTypes.has(type) && skipTypeNameForRoot && !queriedForTypename) {
448 return null;
449 }
450 if (nonOptionalTypename || addTypename || queriedForTypename) {
451 const optionalTypename = !queriedForTypename && !nonOptionalTypename;
452 return {
453 name: `${this._processor.config.formatNamedField('__typename')}${optionalTypename ? '?' : ''}`,
454 type: `'${type.name}'`,
455 };
456 }
457 return null;
458 }
459 getUnknownType() {
460 return 'never';
461 }
462 getEmptyObjectType() {
463 return `{}`;
464 }
465 getEmptyObjectTypeString(mustAddEmptyObject) {
466 return mustAddEmptyObject ? ' | ' + this.getEmptyObjectType() : ``;
467 }
468 transformSelectionSet() {
469 const { grouped, mustAddEmptyObject } = this._buildGroupedSelections();
470 // This might happen in case we have an interface, that is being queries, without any GraphQL
471 // "type" that implements it. It will lead to a runtime error, but we aim to try to reflect that in
472 // build time as well.
473 if (Object.keys(grouped).length === 0) {
474 return this.getUnknownType();
475 }
476 return (Object.keys(grouped)
477 .map(typeName => {
478 const relevant = grouped[typeName].filter(Boolean);
479 if (relevant.length === 0) {
480 return null;
481 }
482 if (relevant.length === 1) {
483 return relevant[0];
484 }
485 return `( ${relevant.join(' & ')} )`;
486 })
487 .filter(Boolean)
488 .join(' | ') + this.getEmptyObjectTypeString(mustAddEmptyObject));
489 }
490 transformFragmentSelectionSetToTypes(fragmentName, fragmentSuffix, declarationBlockConfig) {
491 const { grouped } = this._buildGroupedSelections();
492 const subTypes = Object.keys(grouped)
493 .map(typeName => {
494 const possibleFields = grouped[typeName].filter(Boolean);
495 const declarationName = this.buildFragmentTypeName(fragmentName, fragmentSuffix, typeName);
496 if (possibleFields.length === 0) {
497 if (!this._config.addTypename) {
498 return { name: declarationName, content: this.getEmptyObjectType() };
499 }
500 return null;
501 }
502 return { name: declarationName, content: possibleFields.join(' & ') };
503 })
504 .filter(Boolean);
505 const fragmentTypeName = this.buildFragmentTypeName(fragmentName, fragmentSuffix);
506 const fragmentMaskPartial = this._config.inlineFragmentTypes === 'mask' ? ` & { ' $fragmentName'?: '${fragmentTypeName}' }` : '';
507 if (subTypes.length === 1) {
508 return new utils_js_1.DeclarationBlock(declarationBlockConfig)
509 .export()
510 .asKind('type')
511 .withName(fragmentTypeName)
512 .withContent(subTypes[0].content + fragmentMaskPartial).string;
513 }
514 return [
515 ...subTypes.map(t => new utils_js_1.DeclarationBlock(declarationBlockConfig)
516 .export(this._config.exportFragmentSpreadSubTypes)
517 .asKind('type')
518 .withName(t.name)
519 .withContent(`${t.content}${this._config.inlineFragmentTypes === 'mask' ? ` & { ' $fragmentName'?: '${t.name}' }` : ''}`).string),
520 new utils_js_1.DeclarationBlock(declarationBlockConfig)
521 .export()
522 .asKind('type')
523 .withName(fragmentTypeName)
524 .withContent(subTypes.map(t => t.name).join(' | ')).string,
525 ].join('\n');
526 }
527 buildFragmentTypeName(name, suffix, typeName = '') {
528 return this._convertName(name, {
529 useTypesPrefix: true,
530 suffix: typeName ? `_${typeName}_${suffix}` : suffix,
531 });
532 }
533}
534exports.SelectionSetToObject = SelectionSetToObject;