UNPKG

148 kBJavaScriptView Raw
1import { Kind, isScalarType, isListType, isNonNullType, isObjectType, isAbstractType, isEnumType, isInterfaceType, GraphQLObjectType, isUnionType, print, isTypeSubTypeOf, SchemaMetaFieldDef, TypeMetaFieldDef } from 'graphql';
2import { resolveExternalModuleAndFn, DetailedError, ApolloFederation, getBaseType, oldVisit, removeNonNullWrapper } from '@graphql-codegen/plugin-helpers';
3import { pascalCase } from 'change-case-all';
4import { resolve, relative, dirname, join, isAbsolute, extname, basename } from 'path';
5import parse from 'parse-filepath';
6import autoBind from 'auto-bind';
7import { getRootTypeNames as getRootTypeNames$1, getRootTypes } from '@graphql-tools/utils';
8import { DepGraph } from 'dependency-graph';
9import gqlTag from 'graphql-tag';
10import { optimizeDocumentNode } from '@graphql-tools/optimize';
11import { createHash } from 'crypto';
12import { optimizeDocuments } from '@graphql-tools/relay-operation-optimizer';
13
14const DEFAULT_SCALARS = {
15 ID: 'string',
16 String: 'string',
17 Boolean: 'boolean',
18 Int: 'number',
19 Float: 'number',
20};
21
22function isExternalMapperType(m) {
23 return !!m.import;
24}
25var MapperKind;
26(function (MapperKind) {
27 MapperKind[MapperKind["Namespace"] = 0] = "Namespace";
28 MapperKind[MapperKind["Default"] = 1] = "Default";
29 MapperKind[MapperKind["Regular"] = 2] = "Regular";
30})(MapperKind || (MapperKind = {}));
31function prepareLegacy(mapper) {
32 const items = mapper.split('#');
33 const isNamespace = items.length === 3;
34 const isDefault = items[1].trim() === 'default' || items[1].startsWith('default ');
35 const hasAlias = items[1].includes(' as ');
36 return {
37 items,
38 isDefault,
39 isNamespace,
40 hasAlias,
41 };
42}
43function prepare(mapper) {
44 const [source, path] = mapper.split('#');
45 const isNamespace = path.includes('.');
46 const isDefault = path.trim() === 'default' || path.startsWith('default ');
47 const hasAlias = path.includes(' as ');
48 return {
49 items: isNamespace ? [source, ...path.split('.')] : [source, path],
50 isDefault,
51 isNamespace,
52 hasAlias,
53 };
54}
55function isLegacyMode(mapper) {
56 return mapper.split('#').length === 3;
57}
58function parseMapper(mapper, gqlTypeName = null, suffix) {
59 if (isExternalMapper(mapper)) {
60 const { isNamespace, isDefault, hasAlias, items } = isLegacyMode(mapper) ? prepareLegacy(mapper) : prepare(mapper);
61 const mapperKind = isNamespace
62 ? MapperKind.Namespace
63 : isDefault
64 ? MapperKind.Default
65 : MapperKind.Regular;
66 function handleAlias(isDefault = false) {
67 const [importedType, aliasType] = items[1].split(/\s+as\s+/);
68 const type = maybeSuffix(aliasType);
69 return {
70 importElement: isDefault ? type : `${importedType} as ${type}`,
71 type,
72 };
73 }
74 function maybeSuffix(type) {
75 if (suffix) {
76 return addSuffix(type, suffix);
77 }
78 return type;
79 }
80 function handle() {
81 switch (mapperKind) {
82 // ./my/module#Namespace#Identifier
83 case MapperKind.Namespace: {
84 const [, ns, identifier] = items;
85 return {
86 type: `${ns}.${identifier}`,
87 importElement: ns,
88 };
89 }
90 case MapperKind.Default: {
91 // ./my/module#default as alias
92 if (hasAlias) {
93 return handleAlias(true);
94 }
95 const type = maybeSuffix(`${gqlTypeName}`);
96 // ./my/module#default
97 return {
98 importElement: type,
99 type,
100 };
101 }
102 case MapperKind.Regular: {
103 // ./my/module#Identifier as alias
104 if (hasAlias) {
105 return handleAlias();
106 }
107 const identifier = items[1];
108 const type = maybeSuffix(identifier);
109 // ./my/module#Identifier
110 return {
111 type,
112 importElement: suffix ? `${identifier} as ${type}` : type,
113 };
114 }
115 }
116 }
117 const { type, importElement } = handle();
118 return {
119 default: isDefault,
120 isExternal: true,
121 source: items[0],
122 type,
123 import: importElement.replace(/<(.*?)>/g, ''),
124 };
125 }
126 return {
127 isExternal: false,
128 type: mapper,
129 };
130}
131function addSuffix(element, suffix) {
132 const generic = element.indexOf('<');
133 if (generic === -1) {
134 return `${element}${suffix}`;
135 }
136 return `${element.slice(0, generic)}${suffix}${element.slice(generic)}`;
137}
138function isExternalMapper(value) {
139 return value.includes('#');
140}
141function transformMappers(rawMappers, mapperTypeSuffix) {
142 const result = {};
143 Object.keys(rawMappers).forEach(gqlTypeName => {
144 const mapperDef = rawMappers[gqlTypeName];
145 const parsedMapper = parseMapper(mapperDef, gqlTypeName, mapperTypeSuffix);
146 result[gqlTypeName] = parsedMapper;
147 });
148 return result;
149}
150function transformDirectiveArgumentAndInputFieldMappings(rawDirectiveArgumentAndInputFieldMappings, directiveArgumentAndInputFieldMappingTypeSuffix) {
151 const result = {};
152 Object.keys(rawDirectiveArgumentAndInputFieldMappings).forEach(directive => {
153 const mapperDef = rawDirectiveArgumentAndInputFieldMappings[directive];
154 const parsedMapper = parseMapper(mapperDef, directive, directiveArgumentAndInputFieldMappingTypeSuffix);
155 result[directive] = parsedMapper;
156 });
157 return result;
158}
159function buildMapperImport(source, types, useTypeImports) {
160 if (!types || types.length === 0) {
161 return null;
162 }
163 const defaultType = types.find(t => t.asDefault === true);
164 let namedTypes = types.filter(t => !t.asDefault);
165 if (useTypeImports) {
166 if (defaultType) {
167 // default as Baz
168 namedTypes = [{ identifier: `default as ${defaultType.identifier}` }, ...namedTypes];
169 }
170 // { Foo, Bar as BarModel }
171 const namedImports = namedTypes.length ? `{ ${namedTypes.map(t => t.identifier).join(', ')} }` : '';
172 // { default as Baz, Foo, Bar as BarModel }
173 return `import type ${[namedImports].filter(Boolean).join(', ')} from '${source}';`;
174 }
175 // { Foo, Bar as BarModel }
176 const namedImports = namedTypes.length ? `{ ${namedTypes.map(t => t.identifier).join(', ')} }` : '';
177 // Baz
178 const defaultImport = defaultType ? defaultType.identifier : '';
179 // Baz, { Foo, Bar as BarModel }
180 return `import ${[defaultImport, namedImports].filter(Boolean).join(', ')} from '${source}';`;
181}
182
183const getConfigValue = (value, defaultValue) => {
184 if (value === null || value === undefined) {
185 return defaultValue;
186 }
187 return value;
188};
189function quoteIfNeeded(array, joinWith = ' & ') {
190 if (array.length === 0) {
191 return '';
192 }
193 else if (array.length === 1) {
194 return array[0];
195 }
196 else {
197 return `(${array.join(joinWith)})`;
198 }
199}
200function block(array) {
201 return array && array.length !== 0 ? '{\n' + array.join('\n') + '\n}' : '';
202}
203function wrapWithSingleQuotes(value, skipNumericCheck = false) {
204 if (skipNumericCheck) {
205 if (typeof value === 'number') {
206 return `${value}`;
207 }
208 else {
209 return `'${value}'`;
210 }
211 }
212 if (typeof value === 'number' ||
213 (typeof value === 'string' && !isNaN(parseInt(value)) && parseFloat(value).toString() === value)) {
214 return `${value}`;
215 }
216 return `'${value}'`;
217}
218function breakLine(str) {
219 return str + '\n';
220}
221function indent(str, count = 1) {
222 return new Array(count).fill(' ').join('') + str;
223}
224function indentMultiline(str, count = 1) {
225 const indentation = new Array(count).fill(' ').join('');
226 const replaceWith = '\n' + indentation;
227 return indentation + str.replace(/\n/g, replaceWith);
228}
229function transformComment(comment, indentLevel = 0, disabled = false) {
230 if (!comment || comment === '' || disabled) {
231 return '';
232 }
233 if (isStringValueNode(comment)) {
234 comment = comment.value;
235 }
236 comment = comment.split('*/').join('*\\/');
237 let lines = comment.split('\n');
238 if (lines.length === 1) {
239 return indent(`/** ${lines[0]} */\n`, indentLevel);
240 }
241 lines = ['/**', ...lines.map(line => ` * ${line}`), ' */\n'];
242 return stripTrailingSpaces(lines.map(line => indent(line, indentLevel)).join('\n'));
243}
244class DeclarationBlock {
245 constructor(_config) {
246 this._config = _config;
247 this._decorator = null;
248 this._export = false;
249 this._name = null;
250 this._kind = null;
251 this._methodName = null;
252 this._content = null;
253 this._block = null;
254 this._nameGenerics = null;
255 this._comment = null;
256 this._ignoreBlockWrapper = false;
257 this._config = {
258 blockWrapper: '',
259 blockTransformer: block => block,
260 enumNameValueSeparator: ':',
261 ...this._config,
262 };
263 }
264 withDecorator(decorator) {
265 this._decorator = decorator;
266 return this;
267 }
268 export(exp = true) {
269 if (!this._config.ignoreExport) {
270 this._export = exp;
271 }
272 return this;
273 }
274 asKind(kind) {
275 this._kind = kind;
276 return this;
277 }
278 withComment(comment, disabled = false) {
279 const nonEmptyComment = isStringValueNode(comment) ? !!comment.value : !!comment;
280 if (nonEmptyComment && !disabled) {
281 this._comment = transformComment(comment, 0);
282 }
283 return this;
284 }
285 withMethodCall(methodName, ignoreBlockWrapper = false) {
286 this._methodName = methodName;
287 this._ignoreBlockWrapper = ignoreBlockWrapper;
288 return this;
289 }
290 withBlock(block) {
291 this._block = block;
292 return this;
293 }
294 withContent(content) {
295 this._content = content;
296 return this;
297 }
298 withName(name, generics = null) {
299 this._name = name;
300 this._nameGenerics = generics;
301 return this;
302 }
303 get string() {
304 let result = '';
305 if (this._decorator) {
306 result += this._decorator + '\n';
307 }
308 if (this._export) {
309 result += 'export ';
310 }
311 if (this._kind) {
312 let extra = '';
313 let name = '';
314 if (['type', 'const', 'var', 'let'].includes(this._kind)) {
315 extra = '= ';
316 }
317 if (this._name) {
318 name = this._name + (this._nameGenerics || '') + ' ';
319 }
320 result += this._kind + ' ' + name + extra;
321 }
322 if (this._block) {
323 if (this._content) {
324 result += this._content;
325 }
326 const blockWrapper = this._ignoreBlockWrapper ? '' : this._config.blockWrapper;
327 const before = '{' + blockWrapper;
328 const after = blockWrapper + '}';
329 const block = [before, this._block, after].filter(val => !!val).join('\n');
330 if (this._methodName) {
331 result += `${this._methodName}(${this._config.blockTransformer(block)})`;
332 }
333 else {
334 result += this._config.blockTransformer(block);
335 }
336 }
337 else if (this._content) {
338 result += this._content;
339 }
340 else if (this._kind) {
341 result += this._config.blockTransformer('{}');
342 }
343 return stripTrailingSpaces((this._comment ? this._comment : '') +
344 result +
345 (this._kind === 'interface' || this._kind === 'enum' || this._kind === 'namespace' || this._kind === 'function'
346 ? ''
347 : ';') +
348 '\n');
349 }
350}
351function getBaseTypeNode(typeNode) {
352 if (typeNode.kind === Kind.LIST_TYPE || typeNode.kind === Kind.NON_NULL_TYPE) {
353 return getBaseTypeNode(typeNode.type);
354 }
355 return typeNode;
356}
357function convertNameParts(str, func, removeUnderscore = false) {
358 if (removeUnderscore) {
359 return func(str);
360 }
361 return str
362 .split('_')
363 .map(s => func(s))
364 .join('_');
365}
366function buildScalarsFromConfig(schema, config, defaultScalarsMapping = DEFAULT_SCALARS, defaultScalarType = 'any') {
367 return buildScalars(schema, config.scalars, defaultScalarsMapping, config.strictScalars ? null : config.defaultScalarType || defaultScalarType);
368}
369function buildScalars(schema, scalarsMapping, defaultScalarsMapping = DEFAULT_SCALARS, defaultScalarType = 'any') {
370 const result = {};
371 Object.keys(defaultScalarsMapping).forEach(name => {
372 result[name] = parseMapper(defaultScalarsMapping[name]);
373 });
374 if (schema) {
375 const typeMap = schema.getTypeMap();
376 Object.keys(typeMap)
377 .map(typeName => typeMap[typeName])
378 .filter(type => isScalarType(type))
379 .map((scalarType) => {
380 var _a;
381 const { name } = scalarType;
382 if (typeof scalarsMapping === 'string') {
383 const value = parseMapper(scalarsMapping + '#' + name, name);
384 result[name] = value;
385 }
386 else if (scalarsMapping && typeof scalarsMapping[name] === 'string') {
387 const value = parseMapper(scalarsMapping[name], name);
388 result[name] = value;
389 }
390 else if (scalarsMapping && scalarsMapping[name]) {
391 result[name] = {
392 isExternal: false,
393 type: JSON.stringify(scalarsMapping[name]),
394 };
395 }
396 else if ((_a = scalarType.extensions) === null || _a === void 0 ? void 0 : _a.codegenScalarType) {
397 result[name] = {
398 isExternal: false,
399 type: scalarType.extensions.codegenScalarType,
400 };
401 }
402 else if (!defaultScalarsMapping[name]) {
403 if (defaultScalarType === null) {
404 throw new Error(`Unknown scalar type ${name}. Please override it using the "scalars" configuration field!`);
405 }
406 result[name] = {
407 isExternal: false,
408 type: defaultScalarType,
409 };
410 }
411 });
412 }
413 else if (scalarsMapping) {
414 if (typeof scalarsMapping === 'string') {
415 throw new Error('Cannot use string scalars mapping when building without a schema');
416 }
417 Object.keys(scalarsMapping).forEach(name => {
418 if (typeof scalarsMapping[name] === 'string') {
419 const value = parseMapper(scalarsMapping[name], name);
420 result[name] = value;
421 }
422 else {
423 result[name] = {
424 isExternal: false,
425 type: JSON.stringify(scalarsMapping[name]),
426 };
427 }
428 });
429 }
430 return result;
431}
432function isStringValueNode(node) {
433 return node && typeof node === 'object' && node.kind === Kind.STRING;
434}
435// will be removed on next release because tools already has it
436function getRootTypeNames(schema) {
437 return [schema.getQueryType(), schema.getMutationType(), schema.getSubscriptionType()]
438 .filter(t => t)
439 .map(t => t.name);
440}
441function stripMapperTypeInterpolation(identifier) {
442 return identifier.trim().replace(/<{.*}>/, '');
443}
444const OMIT_TYPE = 'export type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;';
445const REQUIRE_FIELDS_TYPE = `export type RequireFields<T, K extends keyof T> = Omit<T, K> & { [P in K]-?: NonNullable<T[P]> };`;
446/**
447 * merge selection sets into a new selection set without mutating the inputs.
448 */
449function mergeSelectionSets(selectionSet1, selectionSet2) {
450 const newSelections = [...selectionSet1.selections];
451 for (let selection2 of selectionSet2.selections) {
452 if (selection2.kind === 'FragmentSpread' || selection2.kind === 'InlineFragment') {
453 newSelections.push(selection2);
454 continue;
455 }
456 if (selection2.kind !== 'Field') {
457 throw new TypeError('Invalid state.');
458 }
459 const match = newSelections.find(selection1 => selection1.kind === 'Field' &&
460 getFieldNodeNameValue(selection1) === getFieldNodeNameValue(selection2));
461 if (match) {
462 // recursively merge all selection sets
463 if (match.kind === 'Field' && match.selectionSet && selection2.selectionSet) {
464 selection2 = {
465 ...selection2,
466 selectionSet: mergeSelectionSets(match.selectionSet, selection2.selectionSet),
467 };
468 }
469 }
470 newSelections.push(selection2);
471 }
472 return {
473 kind: Kind.SELECTION_SET,
474 selections: newSelections,
475 };
476}
477const getFieldNodeNameValue = (node) => {
478 return (node.alias || node.name).value;
479};
480function separateSelectionSet(selections) {
481 return {
482 fields: selections.filter(s => s.kind === Kind.FIELD),
483 inlines: selections.filter(s => s.kind === Kind.INLINE_FRAGMENT),
484 spreads: selections.filter(s => s.kind === Kind.FRAGMENT_SPREAD),
485 };
486}
487function getPossibleTypes(schema, type) {
488 if (isListType(type) || isNonNullType(type)) {
489 return getPossibleTypes(schema, type.ofType);
490 }
491 else if (isObjectType(type)) {
492 return [type];
493 }
494 else if (isAbstractType(type)) {
495 return schema.getPossibleTypes(type);
496 }
497 return [];
498}
499function hasConditionalDirectives(field) {
500 var _a;
501 const CONDITIONAL_DIRECTIVES = ['skip', 'include'];
502 return (_a = field.directives) === null || _a === void 0 ? void 0 : _a.some(directive => CONDITIONAL_DIRECTIVES.includes(directive.name.value));
503}
504function wrapTypeWithModifiers(baseType, type, options) {
505 let currentType = type;
506 const modifiers = [];
507 while (currentType) {
508 if (isNonNullType(currentType)) {
509 currentType = currentType.ofType;
510 }
511 else {
512 modifiers.push(options.wrapOptional);
513 }
514 if (isListType(currentType)) {
515 modifiers.push(options.wrapArray);
516 currentType = currentType.ofType;
517 }
518 else {
519 break;
520 }
521 }
522 return modifiers.reduceRight((result, modifier) => modifier(result), baseType);
523}
524function removeDescription(nodes) {
525 return nodes.map(node => ({ ...node, description: undefined }));
526}
527function wrapTypeNodeWithModifiers(baseType, typeNode) {
528 switch (typeNode.kind) {
529 case Kind.NAMED_TYPE: {
530 return `Maybe<${baseType}>`;
531 }
532 case Kind.NON_NULL_TYPE: {
533 const innerType = wrapTypeNodeWithModifiers(baseType, typeNode.type);
534 return clearOptional(innerType);
535 }
536 case Kind.LIST_TYPE: {
537 const innerType = wrapTypeNodeWithModifiers(baseType, typeNode.type);
538 return `Maybe<Array<${innerType}>>`;
539 }
540 }
541}
542function clearOptional(str) {
543 const rgx = new RegExp(`^Maybe<(.*?)>$`, 'i');
544 if (str.startsWith(`Maybe`)) {
545 return str.replace(rgx, '$1');
546 }
547 return str;
548}
549function stripTrailingSpaces(str) {
550 return str.replace(/ +\n/g, '\n');
551}
552
553function getKind(node) {
554 if (typeof node === 'string') {
555 return 'typeNames';
556 }
557 if (['EnumValueDefinition', 'EnumValue'].includes(node.kind)) {
558 return 'enumValues';
559 }
560 return 'typeNames';
561}
562function getName(node) {
563 if (node == null) {
564 return undefined;
565 }
566 if (typeof node === 'string') {
567 return node;
568 }
569 switch (node.kind) {
570 case 'OperationDefinition':
571 case 'Variable':
572 case 'Argument':
573 case 'FragmentSpread':
574 case 'FragmentDefinition':
575 case 'ObjectField':
576 case 'Directive':
577 case 'NamedType':
578 case 'ScalarTypeDefinition':
579 case 'ObjectTypeDefinition':
580 case 'FieldDefinition':
581 case 'InputValueDefinition':
582 case 'InterfaceTypeDefinition':
583 case 'UnionTypeDefinition':
584 case 'EnumTypeDefinition':
585 case 'EnumValueDefinition':
586 case 'InputObjectTypeDefinition':
587 case 'DirectiveDefinition': {
588 return getName(node.name);
589 }
590 case 'Name': {
591 return node.value;
592 }
593 case 'Field': {
594 return getName(node.alias || node.name);
595 }
596 case 'VariableDefinition': {
597 return getName(node.variable);
598 }
599 }
600 return undefined;
601}
602function convertFactory(config) {
603 function resolveConventionName(type) {
604 if (!config.namingConvention) {
605 return (str, opts = {}) => {
606 return convertNameParts(str, pascalCase, getConfigValue((opts || {}).transformUnderscore, false));
607 };
608 }
609 if (typeof config.namingConvention === 'string') {
610 if (config.namingConvention === 'keep') {
611 return str => str;
612 }
613 return (str, opts = {}) => {
614 return convertNameParts(str, resolveExternalModuleAndFn(config.namingConvention), getConfigValue((opts || {}).transformUnderscore, false));
615 };
616 }
617 if (typeof config.namingConvention === 'function') {
618 return (str, opts = {}) => {
619 return convertNameParts(str, config.namingConvention, getConfigValue((opts || {}).transformUnderscore, false));
620 };
621 }
622 if (typeof config.namingConvention === 'object' && config.namingConvention[type] === 'keep') {
623 return str => str;
624 }
625 if (typeof config.namingConvention === 'object') {
626 if (!config.namingConvention[type]) {
627 return (str, opts = {}) => {
628 const transformUnderscore = config.namingConvention.transformUnderscore || (opts || {}).transformUnderscore;
629 return convertNameParts(str, pascalCase, getConfigValue(transformUnderscore, false));
630 };
631 }
632 return (str, opts = {}) => {
633 return convertNameParts(str, resolveExternalModuleAndFn(config.namingConvention[type]), getConfigValue((opts || {}).transformUnderscore, true));
634 };
635 }
636 return config.namingConvention[type];
637 }
638 return (node, opts) => {
639 const prefix = opts && opts.prefix;
640 const suffix = opts && opts.suffix;
641 const kind = getKind(node);
642 const str = [prefix || '', getName(node), suffix || ''].join('');
643 return resolveConventionName(kind)(str, opts);
644 };
645}
646
647function escapeString(str) {
648 return str.replace(/\\/g, '\\\\').replace(/\n/g, '\\n').replace(/'/g, "\\'");
649}
650function parseEnumValues({ schema, mapOrStr = {}, ignoreEnumValuesFromSchema, }) {
651 const allTypes = schema.getTypeMap();
652 const allEnums = Object.keys(allTypes).filter(t => isEnumType(allTypes[t]));
653 if (typeof mapOrStr === 'object') {
654 if (!ignoreEnumValuesFromSchema) {
655 for (const enumTypeName of allEnums) {
656 const enumType = schema.getType(enumTypeName);
657 for (const { name, value } of enumType.getValues()) {
658 if (value && value !== name) {
659 mapOrStr[enumTypeName] = mapOrStr[enumTypeName] || {};
660 if (typeof mapOrStr[enumTypeName] !== 'string' && !mapOrStr[enumTypeName][name]) {
661 mapOrStr[enumTypeName][name] = typeof value === 'string' ? escapeString(value) : value;
662 }
663 }
664 }
665 }
666 }
667 const invalidMappings = Object.keys(mapOrStr).filter(gqlName => !allEnums.includes(gqlName));
668 if (invalidMappings.length > 0) {
669 throw new DetailedError(`Invalid 'enumValues' mapping!`, `The following types does not exist in your GraphQL schema: ${invalidMappings.join(', ')}`);
670 }
671 return Object.keys(mapOrStr).reduce((prev, gqlIdentifier) => {
672 const pointer = mapOrStr[gqlIdentifier];
673 if (typeof pointer === 'string') {
674 const mapper = parseMapper(pointer, gqlIdentifier);
675 return {
676 ...prev,
677 [gqlIdentifier]: {
678 isDefault: mapper.isExternal && mapper.default,
679 typeIdentifier: gqlIdentifier,
680 sourceFile: mapper.isExternal ? mapper.source : null,
681 sourceIdentifier: mapper.type,
682 importIdentifier: mapper.isExternal ? mapper.import : null,
683 mappedValues: null,
684 },
685 };
686 }
687 else if (typeof pointer === 'object') {
688 return {
689 ...prev,
690 [gqlIdentifier]: {
691 isDefault: false,
692 typeIdentifier: gqlIdentifier,
693 sourceFile: null,
694 sourceIdentifier: null,
695 importIdentifier: null,
696 mappedValues: pointer,
697 },
698 };
699 }
700 else {
701 throw new DetailedError(`Invalid "enumValues" configuration`, `Enum "${gqlIdentifier}": expected string or object (with enum values mapping)`);
702 }
703 }, {});
704 }
705 else if (typeof mapOrStr === 'string') {
706 return allEnums
707 .filter(enumName => !enumName.startsWith('__'))
708 .reduce((prev, enumName) => {
709 return {
710 ...prev,
711 [enumName]: {
712 isDefault: false,
713 typeIdentifier: enumName,
714 sourceFile: mapOrStr,
715 sourceIdentifier: enumName,
716 importIdentifier: enumName,
717 mappedValues: null,
718 },
719 };
720 }, {});
721 }
722 return {};
723}
724
725const DEFAULT_DECLARATION_KINDS = {
726 directive: 'type',
727 scalar: 'type',
728 input: 'type',
729 type: 'type',
730 interface: 'type',
731 arguments: 'type',
732};
733function normalizeDeclarationKind(declarationKind) {
734 if (typeof declarationKind === 'string') {
735 return {
736 directive: declarationKind,
737 scalar: declarationKind,
738 input: declarationKind,
739 type: declarationKind,
740 interface: declarationKind,
741 arguments: declarationKind,
742 };
743 }
744 return {
745 ...DEFAULT_DECLARATION_KINDS,
746 ...declarationKind,
747 };
748}
749
750const DEFAULT_AVOID_OPTIONALS = {
751 object: false,
752 inputValue: false,
753 field: false,
754 defaultValue: false,
755 resolvers: false,
756};
757function normalizeAvoidOptionals(avoidOptionals) {
758 if (typeof avoidOptionals === 'boolean') {
759 return {
760 object: avoidOptionals,
761 inputValue: avoidOptionals,
762 field: avoidOptionals,
763 defaultValue: avoidOptionals,
764 resolvers: avoidOptionals,
765 };
766 }
767 return {
768 ...DEFAULT_AVOID_OPTIONALS,
769 ...avoidOptionals,
770 };
771}
772
773function generateFragmentImportStatement(statement, kind) {
774 const { importSource: fragmentImportSource, ...rest } = statement;
775 const { identifiers, path, namespace } = fragmentImportSource;
776 const importSource = {
777 identifiers: identifiers
778 .filter(fragmentImport => kind === 'both' || kind === fragmentImport.kind)
779 .map(({ name }) => name),
780 path,
781 namespace,
782 };
783 return generateImportStatement({
784 importSource,
785 ...rest,
786 typesImport: kind === 'type' ? statement.typesImport : false,
787 });
788}
789function generateImportStatement(statement) {
790 const { baseDir, importSource, outputPath, typesImport } = statement;
791 const importPath = resolveImportPath(baseDir, outputPath, importSource.path);
792 const importNames = importSource.identifiers && importSource.identifiers.length
793 ? `{ ${Array.from(new Set(importSource.identifiers)).join(', ')} }`
794 : '*';
795 const importAlias = importSource.namespace ? ` as ${importSource.namespace}` : '';
796 const importStatement = typesImport ? 'import type' : 'import';
797 return `${importStatement} ${importNames}${importAlias} from '${importPath}';${importAlias ? '\n' : ''}`;
798}
799function resolveImportPath(baseDir, outputPath, sourcePath) {
800 const shouldAbsolute = !sourcePath.startsWith('~');
801 if (shouldAbsolute) {
802 const absGeneratedFilePath = resolve(baseDir, outputPath);
803 const absImportFilePath = resolve(baseDir, sourcePath);
804 return resolveRelativeImport(absGeneratedFilePath, absImportFilePath);
805 }
806 else {
807 return sourcePath.replace(`~`, '');
808 }
809}
810function resolveRelativeImport(from, to) {
811 if (!isAbsolute(from)) {
812 throw new Error(`Argument 'from' must be an absolute path, '${from}' given.`);
813 }
814 if (!isAbsolute(to)) {
815 throw new Error(`Argument 'to' must be an absolute path, '${to}' given.`);
816 }
817 return fixLocalFilePath(clearExtension(relative(dirname(from), to)));
818}
819function resolveImportSource(source) {
820 return typeof source === 'string' ? { path: source } : source;
821}
822function clearExtension(path) {
823 const parsedPath = parse(path);
824 return join(parsedPath.dir, parsedPath.name).replace(/\\/g, '/');
825}
826function fixLocalFilePath(path) {
827 return !path.startsWith('..') ? `./${path}` : path;
828}
829
830class BaseVisitor {
831 constructor(rawConfig, additionalConfig) {
832 var _a;
833 this._declarationBlockConfig = {};
834 this._parsedConfig = {
835 convert: convertFactory(rawConfig),
836 typesPrefix: rawConfig.typesPrefix || '',
837 typesSuffix: rawConfig.typesSuffix || '',
838 externalFragments: rawConfig.externalFragments || [],
839 fragmentImports: rawConfig.fragmentImports || [],
840 addTypename: !rawConfig.skipTypename,
841 nonOptionalTypename: !!rawConfig.nonOptionalTypename,
842 useTypeImports: !!rawConfig.useTypeImports,
843 dedupeFragments: !!rawConfig.dedupeFragments,
844 allowEnumStringTypes: !!rawConfig.allowEnumStringTypes,
845 inlineFragmentTypes: (_a = rawConfig.inlineFragmentTypes) !== null && _a !== void 0 ? _a : 'inline',
846 ...(additionalConfig || {}),
847 };
848 this.scalars = {};
849 Object.keys(this.config.scalars || {}).forEach(key => {
850 this.scalars[key] = this.config.scalars[key].type;
851 });
852 autoBind(this);
853 }
854 getVisitorKindContextFromAncestors(ancestors) {
855 if (!ancestors) {
856 return [];
857 }
858 return ancestors.map(t => t.kind).filter(Boolean);
859 }
860 get config() {
861 return this._parsedConfig;
862 }
863 convertName(node, options) {
864 const useTypesPrefix = typeof (options && options.useTypesPrefix) === 'boolean' ? options.useTypesPrefix : true;
865 const useTypesSuffix = typeof (options && options.useTypesSuffix) === 'boolean' ? options.useTypesSuffix : true;
866 let convertedName = '';
867 if (useTypesPrefix) {
868 convertedName += this.config.typesPrefix;
869 }
870 convertedName += this.config.convert(node, options);
871 if (useTypesSuffix) {
872 convertedName += this.config.typesSuffix;
873 }
874 return convertedName;
875 }
876 getOperationSuffix(node, operationType) {
877 const { omitOperationSuffix = false, dedupeOperationSuffix = false } = this.config;
878 const operationName = typeof node === 'string' ? node : node.name ? node.name.value : '';
879 return omitOperationSuffix
880 ? ''
881 : dedupeOperationSuffix && operationName.toLowerCase().endsWith(operationType.toLowerCase())
882 ? ''
883 : operationType;
884 }
885 getFragmentSuffix(node) {
886 return this.getOperationSuffix(node, 'Fragment');
887 }
888 getFragmentName(node) {
889 return this.convertName(node, {
890 suffix: this.getFragmentSuffix(node),
891 useTypesPrefix: false,
892 });
893 }
894 getFragmentVariableName(node) {
895 const { omitOperationSuffix = false, dedupeOperationSuffix = false, fragmentVariableSuffix = 'FragmentDoc', fragmentVariablePrefix = '', } = this.config;
896 const fragmentName = typeof node === 'string' ? node : node.name.value;
897 const suffix = omitOperationSuffix
898 ? ''
899 : dedupeOperationSuffix &&
900 fragmentName.toLowerCase().endsWith('fragment') &&
901 fragmentVariableSuffix.toLowerCase().startsWith('fragment')
902 ? fragmentVariableSuffix.substring('fragment'.length)
903 : fragmentVariableSuffix;
904 return this.convertName(node, {
905 prefix: fragmentVariablePrefix,
906 suffix,
907 useTypesPrefix: false,
908 });
909 }
910 getPunctuation(_declarationKind) {
911 return '';
912 }
913}
914
915class OperationVariablesToObject {
916 constructor(_scalars, _convertName, _namespacedImportName = null, _enumNames = [], _enumPrefix = true, _enumValues = {}, _applyCoercion = false, _directiveArgumentAndInputFieldMappings = {}) {
917 this._scalars = _scalars;
918 this._convertName = _convertName;
919 this._namespacedImportName = _namespacedImportName;
920 this._enumNames = _enumNames;
921 this._enumPrefix = _enumPrefix;
922 this._enumValues = _enumValues;
923 this._applyCoercion = _applyCoercion;
924 this._directiveArgumentAndInputFieldMappings = _directiveArgumentAndInputFieldMappings;
925 autoBind(this);
926 }
927 getName(node) {
928 if (node.name) {
929 if (typeof node.name === 'string') {
930 return node.name;
931 }
932 return node.name.value;
933 }
934 else if (node.variable) {
935 return node.variable.name.value;
936 }
937 return null;
938 }
939 transform(variablesNode) {
940 if (!variablesNode || variablesNode.length === 0) {
941 return null;
942 }
943 return (variablesNode.map(variable => indent(this.transformVariable(variable))).join(`${this.getPunctuation()}\n`) +
944 this.getPunctuation());
945 }
946 getScalar(name) {
947 const prefix = this._namespacedImportName ? `${this._namespacedImportName}.` : '';
948 return `${prefix}Scalars['${name}']`;
949 }
950 getDirectiveMapping(name) {
951 return `DirectiveArgumentAndInputFieldMappings['${name}']`;
952 }
953 getDirectiveOverrideType(directives) {
954 if (!this._directiveArgumentAndInputFieldMappings)
955 return null;
956 const type = directives
957 .map(directive => {
958 const directiveName = directive.name.value;
959 if (this._directiveArgumentAndInputFieldMappings[directiveName]) {
960 return this.getDirectiveMapping(directiveName);
961 }
962 return null;
963 })
964 .reverse()
965 .find(a => !!a);
966 return type || null;
967 }
968 transformVariable(variable) {
969 let typeValue = null;
970 const prefix = this._namespacedImportName ? `${this._namespacedImportName}.` : '';
971 if (typeof variable.type === 'string') {
972 typeValue = variable.type;
973 }
974 else {
975 const baseType = getBaseTypeNode(variable.type);
976 const overrideType = variable.directives ? this.getDirectiveOverrideType(variable.directives) : null;
977 const typeName = baseType.name.value;
978 if (overrideType) {
979 typeValue = overrideType;
980 }
981 else if (this._scalars[typeName]) {
982 typeValue = this.getScalar(typeName);
983 }
984 else if (this._enumValues[typeName] && this._enumValues[typeName].sourceFile) {
985 typeValue = this._enumValues[typeName].typeIdentifier || this._enumValues[typeName].sourceIdentifier;
986 }
987 else {
988 typeValue = `${prefix}${this._convertName(baseType, {
989 useTypesPrefix: this._enumNames.includes(typeName) ? this._enumPrefix : true,
990 })}`;
991 }
992 }
993 const fieldName = this.getName(variable);
994 const fieldType = this.wrapAstTypeWithModifiers(typeValue, variable.type, this._applyCoercion);
995 const hasDefaultValue = variable.defaultValue != null && typeof variable.defaultValue !== 'undefined';
996 const isNonNullType = variable.type.kind === Kind.NON_NULL_TYPE;
997 const formattedFieldString = this.formatFieldString(fieldName, isNonNullType, hasDefaultValue);
998 const formattedTypeString = this.formatTypeString(fieldType, isNonNullType, hasDefaultValue);
999 return `${formattedFieldString}: ${formattedTypeString}`;
1000 }
1001 wrapAstTypeWithModifiers(_baseType, _typeNode, _applyCoercion) {
1002 throw new Error(`You must override "wrapAstTypeWithModifiers" of OperationVariablesToObject!`);
1003 }
1004 formatFieldString(fieldName, isNonNullType, _hasDefaultValue) {
1005 return fieldName;
1006 }
1007 formatTypeString(fieldType, isNonNullType, hasDefaultValue) {
1008 const prefix = this._namespacedImportName ? `${this._namespacedImportName}.` : '';
1009 if (hasDefaultValue) {
1010 return `${prefix}Maybe<${fieldType}>`;
1011 }
1012 return fieldType;
1013 }
1014 getPunctuation() {
1015 return ',';
1016 }
1017}
1018
1019class BaseTypesVisitor extends BaseVisitor {
1020 constructor(_schema, rawConfig, additionalConfig, defaultScalars = DEFAULT_SCALARS) {
1021 var _a;
1022 super(rawConfig, {
1023 enumPrefix: getConfigValue(rawConfig.enumPrefix, true),
1024 onlyEnums: getConfigValue(rawConfig.onlyEnums, false),
1025 onlyOperationTypes: getConfigValue(rawConfig.onlyOperationTypes, false),
1026 addUnderscoreToArgsType: getConfigValue(rawConfig.addUnderscoreToArgsType, false),
1027 enumValues: parseEnumValues({
1028 schema: _schema,
1029 mapOrStr: rawConfig.enumValues,
1030 ignoreEnumValuesFromSchema: rawConfig.ignoreEnumValuesFromSchema,
1031 }),
1032 declarationKind: normalizeDeclarationKind(rawConfig.declarationKind),
1033 scalars: buildScalarsFromConfig(_schema, rawConfig, defaultScalars),
1034 fieldWrapperValue: getConfigValue(rawConfig.fieldWrapperValue, 'T'),
1035 wrapFieldDefinitions: getConfigValue(rawConfig.wrapFieldDefinitions, false),
1036 entireFieldWrapperValue: getConfigValue(rawConfig.entireFieldWrapperValue, 'T'),
1037 wrapEntireDefinitions: getConfigValue(rawConfig.wrapEntireFieldDefinitions, false),
1038 ignoreEnumValuesFromSchema: getConfigValue(rawConfig.ignoreEnumValuesFromSchema, false),
1039 directiveArgumentAndInputFieldMappings: transformDirectiveArgumentAndInputFieldMappings((_a = rawConfig.directiveArgumentAndInputFieldMappings) !== null && _a !== void 0 ? _a : {}, rawConfig.directiveArgumentAndInputFieldMappingTypeSuffix),
1040 ...additionalConfig,
1041 });
1042 this._schema = _schema;
1043 // Note: Missing directive mappers but not a problem since always overriden by implementors
1044 this._argumentsTransformer = new OperationVariablesToObject(this.scalars, this.convertName);
1045 }
1046 getExportPrefix() {
1047 return 'export ';
1048 }
1049 getFieldWrapperValue() {
1050 if (this.config.fieldWrapperValue) {
1051 return `${this.getExportPrefix()}type FieldWrapper<T> = ${this.config.fieldWrapperValue};`;
1052 }
1053 return '';
1054 }
1055 getEntireFieldWrapperValue() {
1056 if (this.config.entireFieldWrapperValue) {
1057 return `${this.getExportPrefix()}type EntireFieldWrapper<T> = ${this.config.entireFieldWrapperValue};`;
1058 }
1059 return '';
1060 }
1061 getScalarsImports() {
1062 return Object.keys(this.config.scalars)
1063 .map(enumName => {
1064 const mappedValue = this.config.scalars[enumName];
1065 if (mappedValue.isExternal) {
1066 return this._buildTypeImport(mappedValue.import, mappedValue.source, mappedValue.default);
1067 }
1068 return null;
1069 })
1070 .filter(a => a);
1071 }
1072 getDirectiveArgumentAndInputFieldMappingsImports() {
1073 return Object.keys(this.config.directiveArgumentAndInputFieldMappings)
1074 .map(directive => {
1075 const mappedValue = this.config.directiveArgumentAndInputFieldMappings[directive];
1076 if (mappedValue.isExternal) {
1077 return this._buildTypeImport(mappedValue.import, mappedValue.source, mappedValue.default);
1078 }
1079 return null;
1080 })
1081 .filter(a => a);
1082 }
1083 get scalarsDefinition() {
1084 if (this.config.onlyEnums)
1085 return '';
1086 const allScalars = Object.keys(this.config.scalars).map(scalarName => {
1087 const scalarValue = this.config.scalars[scalarName].type;
1088 const scalarType = this._schema.getType(scalarName);
1089 const comment = scalarType && scalarType.astNode && scalarType.description ? transformComment(scalarType.description, 1) : '';
1090 const { scalar } = this._parsedConfig.declarationKind;
1091 return comment + indent(`${scalarName}: ${scalarValue}${this.getPunctuation(scalar)}`);
1092 });
1093 return new DeclarationBlock(this._declarationBlockConfig)
1094 .export()
1095 .asKind(this._parsedConfig.declarationKind.scalar)
1096 .withName('Scalars')
1097 .withComment('All built-in and custom scalars, mapped to their actual values')
1098 .withBlock(allScalars.join('\n')).string;
1099 }
1100 get directiveArgumentAndInputFieldMappingsDefinition() {
1101 const directiveEntries = Object.entries(this.config.directiveArgumentAndInputFieldMappings);
1102 if (directiveEntries.length === 0) {
1103 return '';
1104 }
1105 const allDirectives = [];
1106 for (const [directiveName, parsedMapper] of directiveEntries) {
1107 const directiveType = this._schema.getDirective(directiveName);
1108 const comment = (directiveType === null || directiveType === void 0 ? void 0 : directiveType.astNode) && directiveType.description ? transformComment(directiveType.description, 1) : '';
1109 const { directive } = this._parsedConfig.declarationKind;
1110 allDirectives.push(comment + indent(`${directiveName}: ${parsedMapper.type}${this.getPunctuation(directive)}`));
1111 }
1112 return new DeclarationBlock(this._declarationBlockConfig)
1113 .export()
1114 .asKind(this._parsedConfig.declarationKind.directive)
1115 .withName('DirectiveArgumentAndInputFieldMappings')
1116 .withComment('Type overrides using directives')
1117 .withBlock(allDirectives.join('\n')).string;
1118 }
1119 setDeclarationBlockConfig(config) {
1120 this._declarationBlockConfig = config;
1121 }
1122 setArgumentsTransformer(argumentsTransfomer) {
1123 this._argumentsTransformer = argumentsTransfomer;
1124 }
1125 NonNullType(node) {
1126 const asString = node.type;
1127 return asString;
1128 }
1129 getInputObjectDeclarationBlock(node) {
1130 return new DeclarationBlock(this._declarationBlockConfig)
1131 .export()
1132 .asKind(this._parsedConfig.declarationKind.input)
1133 .withName(this.convertName(node))
1134 .withComment(node.description)
1135 .withBlock(node.fields.join('\n'));
1136 }
1137 InputObjectTypeDefinition(node) {
1138 if (this.config.onlyEnums)
1139 return '';
1140 return this.getInputObjectDeclarationBlock(node).string;
1141 }
1142 InputValueDefinition(node) {
1143 if (this.config.onlyEnums)
1144 return '';
1145 const comment = transformComment(node.description, 1);
1146 const { input } = this._parsedConfig.declarationKind;
1147 let type = node.type;
1148 if (node.directives && this.config.directiveArgumentAndInputFieldMappings) {
1149 type = this._getDirectiveOverrideType(node.directives) || type;
1150 }
1151 return comment + indent(`${node.name}: ${type}${this.getPunctuation(input)}`);
1152 }
1153 Name(node) {
1154 return node.value;
1155 }
1156 FieldDefinition(node) {
1157 if (this.config.onlyEnums)
1158 return '';
1159 const typeString = node.type;
1160 const { type } = this._parsedConfig.declarationKind;
1161 const comment = this.getNodeComment(node);
1162 return comment + indent(`${node.name}: ${typeString}${this.getPunctuation(type)}`);
1163 }
1164 UnionTypeDefinition(node, key, parent) {
1165 if (this.config.onlyOperationTypes || this.config.onlyEnums)
1166 return '';
1167 const originalNode = parent[key];
1168 const possibleTypes = originalNode.types
1169 .map(t => (this.scalars[t.name.value] ? this._getScalar(t.name.value) : this.convertName(t)))
1170 .join(' | ');
1171 return new DeclarationBlock(this._declarationBlockConfig)
1172 .export()
1173 .asKind('type')
1174 .withName(this.convertName(node))
1175 .withComment(node.description)
1176 .withContent(possibleTypes).string;
1177 }
1178 mergeInterfaces(interfaces, hasOtherFields) {
1179 return interfaces.join(' & ') + (interfaces.length && hasOtherFields ? ' & ' : '');
1180 }
1181 appendInterfacesAndFieldsToBlock(block, interfaces, fields) {
1182 block.withContent(this.mergeInterfaces(interfaces, fields.length > 0));
1183 block.withBlock(this.mergeAllFields(fields, interfaces.length > 0));
1184 }
1185 getObjectTypeDeclarationBlock(node, originalNode) {
1186 const optionalTypename = this.config.nonOptionalTypename ? '__typename' : '__typename?';
1187 const { type, interface: interfacesType } = this._parsedConfig.declarationKind;
1188 const allFields = [
1189 ...(this.config.addTypename
1190 ? [
1191 indent(`${this.config.immutableTypes ? 'readonly ' : ''}${optionalTypename}: '${node.name}'${this.getPunctuation(type)}`),
1192 ]
1193 : []),
1194 ...node.fields,
1195 ];
1196 const interfacesNames = originalNode.interfaces ? originalNode.interfaces.map(i => this.convertName(i)) : [];
1197 const declarationBlock = new DeclarationBlock(this._declarationBlockConfig)
1198 .export()
1199 .asKind(type)
1200 .withName(this.convertName(node))
1201 .withComment(node.description);
1202 if (type === 'interface' || type === 'class') {
1203 if (interfacesNames.length > 0) {
1204 const keyword = interfacesType === 'interface' && type === 'class' ? 'implements' : 'extends';
1205 declarationBlock.withContent(`${keyword} ` + interfacesNames.join(', ') + (allFields.length > 0 ? ' ' : ' {}'));
1206 }
1207 declarationBlock.withBlock(this.mergeAllFields(allFields, false));
1208 }
1209 else {
1210 this.appendInterfacesAndFieldsToBlock(declarationBlock, interfacesNames, allFields);
1211 }
1212 return declarationBlock;
1213 }
1214 mergeAllFields(allFields, _hasInterfaces) {
1215 return allFields.join('\n');
1216 }
1217 ObjectTypeDefinition(node, key, parent) {
1218 if (this.config.onlyOperationTypes || this.config.onlyEnums)
1219 return '';
1220 const originalNode = parent[key];
1221 return [this.getObjectTypeDeclarationBlock(node, originalNode).string, this.buildArgumentsBlock(originalNode)]
1222 .filter(f => f)
1223 .join('\n\n');
1224 }
1225 getInterfaceTypeDeclarationBlock(node, _originalNode) {
1226 const declarationBlock = new DeclarationBlock(this._declarationBlockConfig)
1227 .export()
1228 .asKind(this._parsedConfig.declarationKind.interface)
1229 .withName(this.convertName(node))
1230 .withComment(node.description);
1231 return declarationBlock.withBlock(node.fields.join('\n'));
1232 }
1233 InterfaceTypeDefinition(node, key, parent) {
1234 if (this.config.onlyOperationTypes || this.config.onlyEnums)
1235 return '';
1236 const originalNode = parent[key];
1237 return [this.getInterfaceTypeDeclarationBlock(node, originalNode).string, this.buildArgumentsBlock(originalNode)]
1238 .filter(f => f)
1239 .join('\n\n');
1240 }
1241 ScalarTypeDefinition(_node) {
1242 // We empty this because we handle scalars in a different way, see constructor.
1243 return '';
1244 }
1245 _buildTypeImport(identifier, source, asDefault = false) {
1246 const { useTypeImports } = this.config;
1247 if (asDefault) {
1248 if (useTypeImports) {
1249 return `import type { default as ${identifier} } from '${source}';`;
1250 }
1251 return `import ${identifier} from '${source}';`;
1252 }
1253 return `import${useTypeImports ? ' type' : ''} { ${identifier} } from '${source}';`;
1254 }
1255 handleEnumValueMapper(typeIdentifier, importIdentifier, sourceIdentifier, sourceFile) {
1256 const importStatement = this._buildTypeImport(importIdentifier || sourceIdentifier, sourceFile);
1257 if (importIdentifier !== sourceIdentifier || sourceIdentifier !== typeIdentifier) {
1258 return [importStatement, `import ${typeIdentifier} = ${sourceIdentifier};`];
1259 }
1260 return [importStatement];
1261 }
1262 getEnumsImports() {
1263 return Object.keys(this.config.enumValues)
1264 .flatMap(enumName => {
1265 const mappedValue = this.config.enumValues[enumName];
1266 if (mappedValue.sourceFile) {
1267 if (mappedValue.isDefault) {
1268 return [this._buildTypeImport(mappedValue.typeIdentifier, mappedValue.sourceFile, true)];
1269 }
1270 return this.handleEnumValueMapper(mappedValue.typeIdentifier, mappedValue.importIdentifier, mappedValue.sourceIdentifier, mappedValue.sourceFile);
1271 }
1272 return [];
1273 })
1274 .filter(Boolean);
1275 }
1276 EnumTypeDefinition(node) {
1277 const enumName = node.name;
1278 // In case of mapped external enum string
1279 if (this.config.enumValues[enumName] && this.config.enumValues[enumName].sourceFile) {
1280 return null;
1281 }
1282 return new DeclarationBlock(this._declarationBlockConfig)
1283 .export()
1284 .asKind('enum')
1285 .withName(this.convertName(node, { useTypesPrefix: this.config.enumPrefix }))
1286 .withComment(node.description)
1287 .withBlock(this.buildEnumValuesBlock(enumName, node.values)).string;
1288 }
1289 // We are using it in order to transform "description" field
1290 StringValue(node) {
1291 return node.value;
1292 }
1293 makeValidEnumIdentifier(identifier) {
1294 if (/^[0-9]/.exec(identifier)) {
1295 return wrapWithSingleQuotes(identifier, true);
1296 }
1297 return identifier;
1298 }
1299 buildEnumValuesBlock(typeName, values) {
1300 const schemaEnumType = this._schema
1301 ? this._schema.getType(typeName)
1302 : undefined;
1303 return values
1304 .map(enumOption => {
1305 const optionName = this.makeValidEnumIdentifier(this.convertName(enumOption, {
1306 useTypesPrefix: false,
1307 transformUnderscore: true,
1308 }));
1309 const comment = this.getNodeComment(enumOption);
1310 const schemaEnumValue = schemaEnumType && !this.config.ignoreEnumValuesFromSchema
1311 ? schemaEnumType.getValue(enumOption.name).value
1312 : undefined;
1313 let enumValue = typeof schemaEnumValue !== 'undefined' ? schemaEnumValue : enumOption.name;
1314 if (this.config.enumValues[typeName] &&
1315 this.config.enumValues[typeName].mappedValues &&
1316 typeof this.config.enumValues[typeName].mappedValues[enumValue] !== 'undefined') {
1317 enumValue = this.config.enumValues[typeName].mappedValues[enumValue];
1318 }
1319 return (comment +
1320 indent(`${optionName}${this._declarationBlockConfig.enumNameValueSeparator} ${wrapWithSingleQuotes(enumValue, typeof schemaEnumValue !== 'undefined')}`));
1321 })
1322 .join(',\n');
1323 }
1324 DirectiveDefinition(_node) {
1325 return '';
1326 }
1327 getArgumentsObjectDeclarationBlock(node, name, field) {
1328 return new DeclarationBlock(this._declarationBlockConfig)
1329 .export()
1330 .asKind(this._parsedConfig.declarationKind.arguments)
1331 .withName(this.convertName(name))
1332 .withComment(node.description)
1333 .withBlock(this._argumentsTransformer.transform(field.arguments));
1334 }
1335 getArgumentsObjectTypeDefinition(node, name, field) {
1336 if (this.config.onlyEnums)
1337 return '';
1338 return this.getArgumentsObjectDeclarationBlock(node, name, field).string;
1339 }
1340 buildArgumentsBlock(node) {
1341 const fieldsWithArguments = node.fields.filter(field => field.arguments && field.arguments.length > 0) || [];
1342 return fieldsWithArguments
1343 .map(field => {
1344 const name = node.name.value +
1345 (this.config.addUnderscoreToArgsType ? '_' : '') +
1346 this.convertName(field, {
1347 useTypesPrefix: false,
1348 useTypesSuffix: false,
1349 }) +
1350 'Args';
1351 return this.getArgumentsObjectTypeDefinition(node, name, field);
1352 })
1353 .join('\n\n');
1354 }
1355 _getScalar(name) {
1356 return `Scalars['${name}']`;
1357 }
1358 _getDirectiveArgumentNadInputFieldMapping(name) {
1359 return `DirectiveArgumentAndInputFieldMappings['${name}']`;
1360 }
1361 _getDirectiveOverrideType(directives) {
1362 const type = directives
1363 .map(directive => {
1364 const directiveName = directive.name;
1365 if (this.config.directiveArgumentAndInputFieldMappings[directiveName]) {
1366 return this._getDirectiveArgumentNadInputFieldMapping(directiveName);
1367 }
1368 return null;
1369 })
1370 .reverse()
1371 .find(a => !!a);
1372 return type || null;
1373 }
1374 _getTypeForNode(node) {
1375 const typeAsString = node.name;
1376 if (this.scalars[typeAsString]) {
1377 return this._getScalar(typeAsString);
1378 }
1379 else if (this.config.enumValues[typeAsString]) {
1380 return this.config.enumValues[typeAsString].typeIdentifier;
1381 }
1382 const schemaType = this._schema.getType(node.name);
1383 if (schemaType && isEnumType(schemaType)) {
1384 return this.convertName(node, { useTypesPrefix: this.config.enumPrefix });
1385 }
1386 return this.convertName(node);
1387 }
1388 NamedType(node, key, parent, path, ancestors) {
1389 const currentVisitContext = this.getVisitorKindContextFromAncestors(ancestors);
1390 const isVisitingInputType = currentVisitContext.includes(Kind.INPUT_OBJECT_TYPE_DEFINITION);
1391 const typeToUse = this._getTypeForNode(node);
1392 if (!isVisitingInputType && this.config.fieldWrapperValue && this.config.wrapFieldDefinitions) {
1393 return `FieldWrapper<${typeToUse}>`;
1394 }
1395 return typeToUse;
1396 }
1397 ListType(node, key, parent, path, ancestors) {
1398 const asString = node.type;
1399 return this.wrapWithListType(asString);
1400 }
1401 SchemaDefinition() {
1402 return null;
1403 }
1404 getNodeComment(node) {
1405 let commentText = node.description;
1406 const deprecationDirective = node.directives.find((v) => v.name === 'deprecated');
1407 if (deprecationDirective) {
1408 const deprecationReason = this.getDeprecationReason(deprecationDirective);
1409 commentText = `${commentText ? `${commentText}\n` : ''}@deprecated ${deprecationReason}`;
1410 }
1411 const comment = transformComment(commentText, 1);
1412 return comment;
1413 }
1414 getDeprecationReason(directive) {
1415 if (directive.name === 'deprecated') {
1416 const hasArguments = directive.arguments.length > 0;
1417 let reason = 'Field no longer supported';
1418 if (hasArguments) {
1419 reason = directive.arguments[0].value;
1420 }
1421 return reason;
1422 }
1423 }
1424 wrapWithListType(str) {
1425 return `Array<${str}>`;
1426 }
1427}
1428
1429function getRootType(operation, schema) {
1430 switch (operation) {
1431 case 'query':
1432 return schema.getQueryType();
1433 case 'mutation':
1434 return schema.getMutationType();
1435 case 'subscription':
1436 return schema.getSubscriptionType();
1437 }
1438 throw new Error(`Unknown operation type: ${operation}`);
1439}
1440class BaseDocumentsVisitor extends BaseVisitor {
1441 constructor(rawConfig, additionalConfig, _schema, defaultScalars = DEFAULT_SCALARS) {
1442 super(rawConfig, {
1443 exportFragmentSpreadSubTypes: getConfigValue(rawConfig.exportFragmentSpreadSubTypes, false),
1444 enumPrefix: getConfigValue(rawConfig.enumPrefix, true),
1445 preResolveTypes: getConfigValue(rawConfig.preResolveTypes, true),
1446 dedupeOperationSuffix: getConfigValue(rawConfig.dedupeOperationSuffix, false),
1447 omitOperationSuffix: getConfigValue(rawConfig.omitOperationSuffix, false),
1448 skipTypeNameForRoot: getConfigValue(rawConfig.skipTypeNameForRoot, false),
1449 namespacedImportName: getConfigValue(rawConfig.namespacedImportName, null),
1450 experimentalFragmentVariables: getConfigValue(rawConfig.experimentalFragmentVariables, false),
1451 addTypename: !rawConfig.skipTypename,
1452 globalNamespace: !!rawConfig.globalNamespace,
1453 operationResultSuffix: getConfigValue(rawConfig.operationResultSuffix, ''),
1454 scalars: buildScalarsFromConfig(_schema, rawConfig, defaultScalars),
1455 ...(additionalConfig || {}),
1456 });
1457 this._schema = _schema;
1458 this._unnamedCounter = 1;
1459 this._globalDeclarations = new Set();
1460 autoBind(this);
1461 this._variablesTransfomer = new OperationVariablesToObject(this.scalars, this.convertName, this.config.namespacedImportName);
1462 }
1463 getGlobalDeclarations(noExport = false) {
1464 return Array.from(this._globalDeclarations).map(t => (noExport ? t : `export ${t}`));
1465 }
1466 setSelectionSetHandler(handler) {
1467 this._selectionSetToObject = handler;
1468 }
1469 setDeclarationBlockConfig(config) {
1470 this._declarationBlockConfig = config;
1471 }
1472 setVariablesTransformer(variablesTransfomer) {
1473 this._variablesTransfomer = variablesTransfomer;
1474 }
1475 get schema() {
1476 return this._schema;
1477 }
1478 get addTypename() {
1479 return this._parsedConfig.addTypename;
1480 }
1481 handleAnonymousOperation(node) {
1482 const name = node.name && node.name.value;
1483 if (name) {
1484 return this.convertName(name, {
1485 useTypesPrefix: false,
1486 useTypesSuffix: false,
1487 });
1488 }
1489 return this.convertName(this._unnamedCounter++ + '', {
1490 prefix: 'Unnamed_',
1491 suffix: '_',
1492 useTypesPrefix: false,
1493 useTypesSuffix: false,
1494 });
1495 }
1496 FragmentDefinition(node) {
1497 const fragmentRootType = this._schema.getType(node.typeCondition.name.value);
1498 const selectionSet = this._selectionSetToObject.createNext(fragmentRootType, node.selectionSet);
1499 const fragmentSuffix = this.getFragmentSuffix(node);
1500 return [
1501 selectionSet.transformFragmentSelectionSetToTypes(node.name.value, fragmentSuffix, this._declarationBlockConfig),
1502 this.config.experimentalFragmentVariables
1503 ? new DeclarationBlock({
1504 ...this._declarationBlockConfig,
1505 blockTransformer: t => this.applyVariablesWrapper(t),
1506 })
1507 .export()
1508 .asKind('type')
1509 .withName(this.convertName(node.name.value, {
1510 suffix: fragmentSuffix + 'Variables',
1511 }))
1512 .withBlock(this._variablesTransfomer.transform(node.variableDefinitions)).string
1513 : undefined,
1514 ]
1515 .filter(r => r)
1516 .join('\n\n');
1517 }
1518 applyVariablesWrapper(variablesBlock) {
1519 return variablesBlock;
1520 }
1521 OperationDefinition(node) {
1522 const name = this.handleAnonymousOperation(node);
1523 const operationRootType = getRootType(node.operation, this._schema);
1524 if (!operationRootType) {
1525 throw new Error(`Unable to find root schema type for operation type "${node.operation}"!`);
1526 }
1527 const selectionSet = this._selectionSetToObject.createNext(operationRootType, node.selectionSet);
1528 const visitedOperationVariables = this._variablesTransfomer.transform(node.variableDefinitions);
1529 const operationType = pascalCase(node.operation);
1530 const operationTypeSuffix = this.getOperationSuffix(name, operationType);
1531 const operationResult = new DeclarationBlock(this._declarationBlockConfig)
1532 .export()
1533 .asKind('type')
1534 .withName(this.convertName(name, {
1535 suffix: operationTypeSuffix + this._parsedConfig.operationResultSuffix,
1536 }))
1537 .withContent(selectionSet.transformSelectionSet()).string;
1538 const operationVariables = new DeclarationBlock({
1539 ...this._declarationBlockConfig,
1540 blockTransformer: t => this.applyVariablesWrapper(t),
1541 })
1542 .export()
1543 .asKind('type')
1544 .withName(this.convertName(name, {
1545 suffix: operationTypeSuffix + 'Variables',
1546 }))
1547 .withBlock(visitedOperationVariables).string;
1548 return [operationVariables, operationResult].filter(r => r).join('\n\n');
1549 }
1550}
1551
1552class BaseResolversVisitor extends BaseVisitor {
1553 constructor(rawConfig, additionalConfig, _schema, defaultScalars = DEFAULT_SCALARS) {
1554 var _a;
1555 super(rawConfig, {
1556 immutableTypes: getConfigValue(rawConfig.immutableTypes, false),
1557 optionalResolveType: getConfigValue(rawConfig.optionalResolveType, false),
1558 enumPrefix: getConfigValue(rawConfig.enumPrefix, true),
1559 federation: getConfigValue(rawConfig.federation, false),
1560 resolverTypeWrapperSignature: getConfigValue(rawConfig.resolverTypeWrapperSignature, 'Promise<T> | T'),
1561 enumValues: parseEnumValues({
1562 schema: _schema,
1563 mapOrStr: rawConfig.enumValues,
1564 }),
1565 addUnderscoreToArgsType: getConfigValue(rawConfig.addUnderscoreToArgsType, false),
1566 onlyResolveTypeForInterfaces: getConfigValue(rawConfig.onlyResolveTypeForInterfaces, false),
1567 contextType: parseMapper(rawConfig.contextType || 'any', 'ContextType'),
1568 fieldContextTypes: getConfigValue(rawConfig.fieldContextTypes, []),
1569 directiveContextTypes: getConfigValue(rawConfig.directiveContextTypes, []),
1570 resolverTypeSuffix: getConfigValue(rawConfig.resolverTypeSuffix, 'Resolvers'),
1571 allResolversTypeName: getConfigValue(rawConfig.allResolversTypeName, 'Resolvers'),
1572 rootValueType: parseMapper(rawConfig.rootValueType || '{}', 'RootValueType'),
1573 namespacedImportName: getConfigValue(rawConfig.namespacedImportName, ''),
1574 avoidOptionals: getConfigValue(rawConfig.avoidOptionals, false),
1575 defaultMapper: rawConfig.defaultMapper
1576 ? parseMapper(rawConfig.defaultMapper || 'any', 'DefaultMapperType')
1577 : null,
1578 mappers: transformMappers(rawConfig.mappers || {}, rawConfig.mapperTypeSuffix),
1579 scalars: buildScalarsFromConfig(_schema, rawConfig, defaultScalars),
1580 internalResolversPrefix: getConfigValue(rawConfig.internalResolversPrefix, '__'),
1581 ...additionalConfig,
1582 });
1583 this._schema = _schema;
1584 this._declarationBlockConfig = {};
1585 this._collectedResolvers = {};
1586 this._collectedDirectiveResolvers = {};
1587 this._usedMappers = {};
1588 this._resolversTypes = {};
1589 this._resolversParentTypes = {};
1590 this._rootTypeNames = new Set();
1591 this._globalDeclarations = new Set();
1592 this._hasScalars = false;
1593 this._hasFederation = false;
1594 this._shouldMapType = {};
1595 autoBind(this);
1596 this._federation = new ApolloFederation({ enabled: this.config.federation, schema: this.schema });
1597 this._rootTypeNames = getRootTypeNames$1(_schema);
1598 this._variablesTransformer = new OperationVariablesToObject(this.scalars, this.convertName, this.config.namespacedImportName);
1599 this._resolversTypes = this.createResolversFields(type => this.applyResolverTypeWrapper(type), type => this.clearResolverTypeWrapper(type), name => this.getTypeToUse(name));
1600 this._resolversParentTypes = this.createResolversFields(type => type, type => type, name => this.getParentTypeToUse(name), namedType => !isEnumType(namedType));
1601 this._fieldContextTypeMap = this.createFieldContextTypeMap();
1602 this._directiveContextTypesMap = this.createDirectivedContextType();
1603 this._directiveResolverMappings = (_a = rawConfig.directiveResolverMappings) !== null && _a !== void 0 ? _a : {};
1604 }
1605 getResolverTypeWrapperSignature() {
1606 return `export type ResolverTypeWrapper<T> = ${this.config.resolverTypeWrapperSignature};`;
1607 }
1608 shouldMapType(type, duringCheck = []) {
1609 if (type.name.startsWith('__') || this.config.scalars[type.name]) {
1610 return false;
1611 }
1612 if (this.config.mappers[type.name]) {
1613 return true;
1614 }
1615 if (isObjectType(type) || isInterfaceType(type)) {
1616 const fields = type.getFields();
1617 return Object.keys(fields)
1618 .filter(fieldName => {
1619 const field = fields[fieldName];
1620 const fieldType = getBaseType(field.type);
1621 return !duringCheck.includes(fieldType.name);
1622 })
1623 .some(fieldName => {
1624 const field = fields[fieldName];
1625 const fieldType = getBaseType(field.type);
1626 if (this._shouldMapType[fieldType.name] !== undefined) {
1627 return this._shouldMapType[fieldType.name];
1628 }
1629 if (this.config.mappers[type.name]) {
1630 return true;
1631 }
1632 duringCheck.push(type.name);
1633 const innerResult = this.shouldMapType(fieldType, duringCheck);
1634 return innerResult;
1635 });
1636 }
1637 return false;
1638 }
1639 convertName(node, options, applyNamespacedImport = false) {
1640 const sourceType = super.convertName(node, options);
1641 return `${applyNamespacedImport && this.config.namespacedImportName ? this.config.namespacedImportName + '.' : ''}${sourceType}`;
1642 }
1643 // Kamil: this one is heeeeavvyyyy
1644 createResolversFields(applyWrapper, clearWrapper, getTypeToUse, shouldInclude) {
1645 const allSchemaTypes = this._schema.getTypeMap();
1646 const typeNames = this._federation.filterTypeNames(Object.keys(allSchemaTypes));
1647 // avoid checking all types recursively if we have no `mappers` defined
1648 if (Object.keys(this.config.mappers).length > 0) {
1649 typeNames.forEach(typeName => {
1650 if (this._shouldMapType[typeName] === undefined) {
1651 const schemaType = allSchemaTypes[typeName];
1652 this._shouldMapType[typeName] = this.shouldMapType(schemaType);
1653 }
1654 });
1655 }
1656 return typeNames.reduce((prev, typeName) => {
1657 const schemaType = allSchemaTypes[typeName];
1658 if (typeName.startsWith('__') || (shouldInclude && !shouldInclude(schemaType))) {
1659 return prev;
1660 }
1661 let shouldApplyOmit = false;
1662 const isRootType = this._rootTypeNames.has(typeName);
1663 const isMapped = this.config.mappers[typeName];
1664 const isScalar = this.config.scalars[typeName];
1665 const hasDefaultMapper = !!(this.config.defaultMapper && this.config.defaultMapper.type);
1666 if (isRootType) {
1667 prev[typeName] = applyWrapper(this.config.rootValueType.type);
1668 return prev;
1669 }
1670 else if (isMapped && this.config.mappers[typeName].type) {
1671 this.markMapperAsUsed(typeName);
1672 prev[typeName] = applyWrapper(this.config.mappers[typeName].type);
1673 }
1674 else if (isInterfaceType(schemaType)) {
1675 const allTypesMap = this._schema.getTypeMap();
1676 const implementingTypes = [];
1677 for (const graphqlType of Object.values(allTypesMap)) {
1678 if (graphqlType instanceof GraphQLObjectType) {
1679 const allInterfaces = graphqlType.getInterfaces();
1680 if (allInterfaces.some(int => int.name === schemaType.name)) {
1681 implementingTypes.push(graphqlType.name);
1682 }
1683 }
1684 }
1685 const possibleTypes = implementingTypes.map(name => getTypeToUse(name)).join(' | ') || 'never';
1686 prev[typeName] = possibleTypes;
1687 return prev;
1688 }
1689 else if (isEnumType(schemaType) && this.config.enumValues[typeName]) {
1690 prev[typeName] =
1691 this.config.enumValues[typeName].sourceIdentifier ||
1692 this.convertName(this.config.enumValues[typeName].typeIdentifier);
1693 }
1694 else if (hasDefaultMapper && !hasPlaceholder(this.config.defaultMapper.type)) {
1695 prev[typeName] = applyWrapper(this.config.defaultMapper.type);
1696 }
1697 else if (isScalar) {
1698 prev[typeName] = applyWrapper(this._getScalar(typeName));
1699 }
1700 else if (isUnionType(schemaType)) {
1701 prev[typeName] = schemaType
1702 .getTypes()
1703 .map(type => getTypeToUse(type.name))
1704 .join(' | ');
1705 }
1706 else if (isEnumType(schemaType)) {
1707 prev[typeName] = this.convertName(typeName, { useTypesPrefix: this.config.enumPrefix }, true);
1708 }
1709 else {
1710 shouldApplyOmit = true;
1711 prev[typeName] = this.convertName(typeName, {}, true);
1712 }
1713 if (shouldApplyOmit && prev[typeName] !== 'any' && isObjectType(schemaType)) {
1714 const fields = schemaType.getFields();
1715 const relevantFields = this._federation
1716 .filterFieldNames(Object.keys(fields))
1717 .filter(fieldName => {
1718 const field = fields[fieldName];
1719 const baseType = getBaseType(field.type);
1720 // Filter out fields of types that are not included
1721 if (shouldInclude && !shouldInclude(baseType)) {
1722 return false;
1723 }
1724 return true;
1725 })
1726 .map(fieldName => {
1727 const field = fields[fieldName];
1728 const baseType = getBaseType(field.type);
1729 const isUnion = isUnionType(baseType);
1730 if (!this.config.mappers[baseType.name] && !isUnion && !this._shouldMapType[baseType.name]) {
1731 return null;
1732 }
1733 const addOptionalSign = !this.config.avoidOptionals && !isNonNullType(field.type);
1734 return {
1735 addOptionalSign,
1736 fieldName,
1737 replaceWithType: wrapTypeWithModifiers(getTypeToUse(baseType.name), field.type, {
1738 wrapOptional: this.applyMaybe,
1739 wrapArray: this.wrapWithArray,
1740 }),
1741 };
1742 })
1743 .filter(a => a);
1744 if (relevantFields.length > 0) {
1745 // Puts ResolverTypeWrapper on top of an entire type
1746 prev[typeName] = applyWrapper(this.replaceFieldsInType(prev[typeName], relevantFields));
1747 }
1748 else {
1749 // We still want to use ResolverTypeWrapper, even if we don't touch any fields
1750 prev[typeName] = applyWrapper(prev[typeName]);
1751 }
1752 }
1753 if (isMapped && hasPlaceholder(prev[typeName])) {
1754 prev[typeName] = replacePlaceholder(prev[typeName], typeName);
1755 }
1756 if (!isMapped && hasDefaultMapper && hasPlaceholder(this.config.defaultMapper.type)) {
1757 // Make sure the inner type has no ResolverTypeWrapper
1758 const name = clearWrapper(isScalar ? this._getScalar(typeName) : prev[typeName]);
1759 const replaced = replacePlaceholder(this.config.defaultMapper.type, name);
1760 // Don't wrap Union with ResolverTypeWrapper, each inner type already has it
1761 if (isUnionType(schemaType)) {
1762 prev[typeName] = replaced;
1763 }
1764 else {
1765 prev[typeName] = applyWrapper(replacePlaceholder(this.config.defaultMapper.type, name));
1766 }
1767 }
1768 return prev;
1769 }, {});
1770 }
1771 replaceFieldsInType(typeName, relevantFields) {
1772 this._globalDeclarations.add(OMIT_TYPE);
1773 return `Omit<${typeName}, ${relevantFields.map(f => `'${f.fieldName}'`).join(' | ')}> & { ${relevantFields
1774 .map(f => `${f.fieldName}${f.addOptionalSign ? '?' : ''}: ${f.replaceWithType}`)
1775 .join(', ')} }`;
1776 }
1777 applyMaybe(str) {
1778 const namespacedImportPrefix = this.config.namespacedImportName ? this.config.namespacedImportName + '.' : '';
1779 return `${namespacedImportPrefix}Maybe<${str}>`;
1780 }
1781 applyResolverTypeWrapper(str) {
1782 return `ResolverTypeWrapper<${this.clearResolverTypeWrapper(str)}>`;
1783 }
1784 clearMaybe(str) {
1785 const namespacedImportPrefix = this.config.namespacedImportName ? this.config.namespacedImportName + '.' : '';
1786 if (str.startsWith(`${namespacedImportPrefix}Maybe<`)) {
1787 const maybeRe = new RegExp(`${namespacedImportPrefix.replace('.', '\\.')}Maybe<(.*?)>$`);
1788 return str.replace(maybeRe, '$1');
1789 }
1790 return str;
1791 }
1792 clearResolverTypeWrapper(str) {
1793 if (str.startsWith('ResolverTypeWrapper<')) {
1794 return str.replace(/ResolverTypeWrapper<(.*?)>$/, '$1');
1795 }
1796 return str;
1797 }
1798 wrapWithArray(t) {
1799 if (this.config.immutableTypes) {
1800 return `ReadonlyArray<${t}>`;
1801 }
1802 return `Array<${t}>`;
1803 }
1804 createFieldContextTypeMap() {
1805 return this.config.fieldContextTypes.reduce((prev, fieldContextType) => {
1806 const items = fieldContextType.split('#');
1807 if (items.length === 3) {
1808 const [path, source, contextTypeName] = items;
1809 return { ...prev, [path]: parseMapper(`${source}#${contextTypeName}`) };
1810 }
1811 const [path, contextType] = items;
1812 return { ...prev, [path]: parseMapper(contextType) };
1813 }, {});
1814 }
1815 createDirectivedContextType() {
1816 return this.config.directiveContextTypes.reduce((prev, fieldContextType) => {
1817 const items = fieldContextType.split('#');
1818 if (items.length === 3) {
1819 const [path, source, contextTypeName] = items;
1820 return { ...prev, [path]: parseMapper(`${source}#${contextTypeName}`) };
1821 }
1822 const [path, contextType] = items;
1823 return { ...prev, [path]: parseMapper(contextType) };
1824 }, {});
1825 }
1826 buildResolversTypes() {
1827 const declarationKind = 'type';
1828 return new DeclarationBlock(this._declarationBlockConfig)
1829 .export()
1830 .asKind(declarationKind)
1831 .withName(this.convertName('ResolversTypes'))
1832 .withComment('Mapping between all available schema types and the resolvers types')
1833 .withBlock(Object.keys(this._resolversTypes)
1834 .map(typeName => indent(`${typeName}: ${this._resolversTypes[typeName]}${this.getPunctuation(declarationKind)}`))
1835 .join('\n')).string;
1836 }
1837 buildResolversParentTypes() {
1838 const declarationKind = 'type';
1839 return new DeclarationBlock(this._declarationBlockConfig)
1840 .export()
1841 .asKind(declarationKind)
1842 .withName(this.convertName('ResolversParentTypes'))
1843 .withComment('Mapping between all available schema types and the resolvers parents')
1844 .withBlock(Object.keys(this._resolversParentTypes)
1845 .map(typeName => indent(`${typeName}: ${this._resolversParentTypes[typeName]}${this.getPunctuation(declarationKind)}`))
1846 .join('\n')).string;
1847 }
1848 get schema() {
1849 return this._schema;
1850 }
1851 get defaultMapperType() {
1852 return this.config.defaultMapper.type;
1853 }
1854 get unusedMappers() {
1855 return Object.keys(this.config.mappers).filter(name => !this._usedMappers[name]);
1856 }
1857 get globalDeclarations() {
1858 return Array.from(this._globalDeclarations);
1859 }
1860 isMapperImported(groupedMappers, identifier, source) {
1861 const exists = !groupedMappers[source] ? false : !!groupedMappers[source].find(m => m.identifier === identifier);
1862 const existsFromEnums = !!Object.keys(this.config.enumValues)
1863 .map(key => this.config.enumValues[key])
1864 .find(o => o.sourceFile === source && o.typeIdentifier === identifier);
1865 return exists || existsFromEnums;
1866 }
1867 get mappersImports() {
1868 const groupedMappers = {};
1869 const addMapper = (source, identifier, asDefault) => {
1870 if (!this.isMapperImported(groupedMappers, identifier, source)) {
1871 if (!groupedMappers[source]) {
1872 groupedMappers[source] = [];
1873 }
1874 groupedMappers[source].push({ identifier, asDefault });
1875 }
1876 };
1877 Object.keys(this.config.mappers)
1878 .map(gqlTypeName => ({ gqlType: gqlTypeName, mapper: this.config.mappers[gqlTypeName] }))
1879 .filter(({ mapper }) => mapper.isExternal)
1880 .forEach(({ mapper }) => {
1881 const externalMapper = mapper;
1882 const identifier = stripMapperTypeInterpolation(externalMapper.import);
1883 addMapper(externalMapper.source, identifier, externalMapper.default);
1884 });
1885 if (this.config.contextType.isExternal) {
1886 addMapper(this.config.contextType.source, this.config.contextType.import, this.config.contextType.default);
1887 }
1888 if (this.config.rootValueType.isExternal) {
1889 addMapper(this.config.rootValueType.source, this.config.rootValueType.import, this.config.rootValueType.default);
1890 }
1891 if (this.config.defaultMapper && this.config.defaultMapper.isExternal) {
1892 const identifier = stripMapperTypeInterpolation(this.config.defaultMapper.import);
1893 addMapper(this.config.defaultMapper.source, identifier, this.config.defaultMapper.default);
1894 }
1895 Object.values(this._fieldContextTypeMap).forEach(parsedMapper => {
1896 if (parsedMapper.isExternal) {
1897 addMapper(parsedMapper.source, parsedMapper.import, parsedMapper.default);
1898 }
1899 });
1900 Object.values(this._directiveContextTypesMap).forEach(parsedMapper => {
1901 if (parsedMapper.isExternal) {
1902 addMapper(parsedMapper.source, parsedMapper.import, parsedMapper.default);
1903 }
1904 });
1905 return Object.keys(groupedMappers)
1906 .map(source => buildMapperImport(source, groupedMappers[source], this.config.useTypeImports))
1907 .filter(Boolean);
1908 }
1909 setDeclarationBlockConfig(config) {
1910 this._declarationBlockConfig = config;
1911 }
1912 setVariablesTransformer(variablesTransfomer) {
1913 this._variablesTransformer = variablesTransfomer;
1914 }
1915 hasScalars() {
1916 return this._hasScalars;
1917 }
1918 hasFederation() {
1919 return this._hasFederation;
1920 }
1921 getRootResolver() {
1922 const name = this.convertName(this.config.allResolversTypeName);
1923 const declarationKind = 'type';
1924 const contextType = `<ContextType = ${this.config.contextType.type}>`;
1925 return [
1926 new DeclarationBlock(this._declarationBlockConfig)
1927 .export()
1928 .asKind(declarationKind)
1929 .withName(name, contextType)
1930 .withBlock(Object.keys(this._collectedResolvers)
1931 .map(schemaTypeName => {
1932 const resolverType = this._collectedResolvers[schemaTypeName];
1933 return indent(this.formatRootResolver(schemaTypeName, resolverType, declarationKind));
1934 })
1935 .join('\n')).string,
1936 ].join('\n');
1937 }
1938 formatRootResolver(schemaTypeName, resolverType, declarationKind) {
1939 return `${schemaTypeName}${this.config.avoidOptionals ? '' : '?'}: ${resolverType}${this.getPunctuation(declarationKind)}`;
1940 }
1941 getAllDirectiveResolvers() {
1942 if (Object.keys(this._collectedDirectiveResolvers).length) {
1943 const declarationKind = 'type';
1944 const name = this.convertName('DirectiveResolvers');
1945 const contextType = `<ContextType = ${this.config.contextType.type}>`;
1946 return [
1947 new DeclarationBlock(this._declarationBlockConfig)
1948 .export()
1949 .asKind(declarationKind)
1950 .withName(name, contextType)
1951 .withBlock(Object.keys(this._collectedDirectiveResolvers)
1952 .map(schemaTypeName => {
1953 const resolverType = this._collectedDirectiveResolvers[schemaTypeName];
1954 return indent(this.formatRootResolver(schemaTypeName, resolverType, declarationKind));
1955 })
1956 .join('\n')).string,
1957 ].join('\n');
1958 }
1959 return '';
1960 }
1961 Name(node) {
1962 return node.value;
1963 }
1964 ListType(node) {
1965 const asString = node.type;
1966 return this.wrapWithArray(asString);
1967 }
1968 _getScalar(name) {
1969 return `${this.config.namespacedImportName ? this.config.namespacedImportName + '.' : ''}Scalars['${name}']`;
1970 }
1971 NamedType(node) {
1972 const nameStr = node.name;
1973 if (this.config.scalars[nameStr]) {
1974 return this._getScalar(nameStr);
1975 }
1976 return this.convertName(node, null, true);
1977 }
1978 NonNullType(node) {
1979 const asString = node.type;
1980 return asString;
1981 }
1982 markMapperAsUsed(name) {
1983 this._usedMappers[name] = true;
1984 }
1985 getTypeToUse(name) {
1986 const resolversType = this.convertName('ResolversTypes');
1987 return `${resolversType}['${name}']`;
1988 }
1989 getParentTypeToUse(name) {
1990 const resolversType = this.convertName('ResolversParentTypes');
1991 return `${resolversType}['${name}']`;
1992 }
1993 getParentTypeForSignature(_node) {
1994 return 'ParentType';
1995 }
1996 transformParentGenericType(parentType) {
1997 return `ParentType extends ${parentType} = ${parentType}`;
1998 }
1999 FieldDefinition(node, key, parent) {
2000 const hasArguments = node.arguments && node.arguments.length > 0;
2001 const declarationKind = 'type';
2002 return (parentName) => {
2003 var _a, _b, _c, _d, _e;
2004 const original = parent[key];
2005 const baseType = getBaseTypeNode(original.type);
2006 const realType = baseType.name.value;
2007 const parentType = this.schema.getType(parentName);
2008 if (this._federation.skipField({ fieldNode: original, parentType })) {
2009 return null;
2010 }
2011 const contextType = this.getContextType(parentName, node);
2012 const typeToUse = this.getTypeToUse(realType);
2013 const mappedType = this._variablesTransformer.wrapAstTypeWithModifiers(typeToUse, original.type);
2014 const subscriptionType = this._schema.getSubscriptionType();
2015 const isSubscriptionType = subscriptionType && subscriptionType.name === parentName;
2016 let argsType = hasArguments
2017 ? this.convertName(parentName +
2018 (this.config.addUnderscoreToArgsType ? '_' : '') +
2019 this.convertName(node.name, {
2020 useTypesPrefix: false,
2021 useTypesSuffix: false,
2022 }) +
2023 'Args', {
2024 useTypesPrefix: true,
2025 }, true)
2026 : null;
2027 if (argsType !== null) {
2028 const argsToForceRequire = original.arguments.filter(arg => !!arg.defaultValue || arg.type.kind === 'NonNullType');
2029 if (argsToForceRequire.length > 0) {
2030 argsType = this.applyRequireFields(argsType, argsToForceRequire);
2031 }
2032 else if (original.arguments.length > 0) {
2033 argsType = this.applyOptionalFields(argsType, original.arguments);
2034 }
2035 }
2036 const parentTypeSignature = this._federation.transformParentType({
2037 fieldNode: original,
2038 parentType,
2039 parentTypeSignature: this.getParentTypeForSignature(node),
2040 });
2041 const mappedTypeKey = isSubscriptionType ? `${mappedType}, "${node.name}"` : mappedType;
2042 const directiveMappings = (_b = (_a = node.directives) === null || _a === void 0 ? void 0 : _a.map(directive => this._directiveResolverMappings[directive.name]).filter(Boolean).reverse()) !== null && _b !== void 0 ? _b : [];
2043 const resolverType = isSubscriptionType ? 'SubscriptionResolver' : (_c = directiveMappings[0]) !== null && _c !== void 0 ? _c : 'Resolver';
2044 const avoidOptionals = (_e = (_d = this.config.avoidOptionals) === null || _d === void 0 ? void 0 : _d.resolvers) !== null && _e !== void 0 ? _e : this.config.avoidOptionals === true;
2045 const signature = {
2046 name: node.name,
2047 modifier: avoidOptionals ? '' : '?',
2048 type: resolverType,
2049 genericTypes: [mappedTypeKey, parentTypeSignature, contextType, argsType].filter(f => f),
2050 };
2051 if (this._federation.isResolveReferenceField(node)) {
2052 this._hasFederation = true;
2053 signature.type = 'ReferenceResolver';
2054 if (signature.genericTypes.length >= 3) {
2055 signature.genericTypes = signature.genericTypes.slice(0, 3);
2056 }
2057 }
2058 return indent(`${signature.name}${signature.modifier}: ${signature.type}<${signature.genericTypes.join(', ')}>${this.getPunctuation(declarationKind)}`);
2059 };
2060 }
2061 getFieldContextType(parentName, node) {
2062 if (this._fieldContextTypeMap[`${parentName}.${node.name}`]) {
2063 return this._fieldContextTypeMap[`${parentName}.${node.name}`].type;
2064 }
2065 return 'ContextType';
2066 }
2067 getContextType(parentName, node) {
2068 let contextType = this.getFieldContextType(parentName, node);
2069 for (const directive of node.directives) {
2070 const name = directive.name;
2071 const directiveMap = this._directiveContextTypesMap[name];
2072 if (directiveMap) {
2073 contextType = `${directiveMap.type}<${contextType}>`;
2074 }
2075 }
2076 return contextType;
2077 }
2078 applyRequireFields(argsType, fields) {
2079 this._globalDeclarations.add(REQUIRE_FIELDS_TYPE);
2080 return `RequireFields<${argsType}, ${fields.map(f => `'${f.name.value}'`).join(' | ')}>`;
2081 }
2082 applyOptionalFields(argsType, _fields) {
2083 return `Partial<${argsType}>`;
2084 }
2085 ObjectTypeDefinition(node) {
2086 var _a, _b, _c;
2087 const declarationKind = 'type';
2088 const name = this.convertName(node, {
2089 suffix: this.config.resolverTypeSuffix,
2090 });
2091 const typeName = node.name;
2092 const parentType = this.getParentTypeToUse(typeName);
2093 const isRootType = [
2094 (_a = this.schema.getQueryType()) === null || _a === void 0 ? void 0 : _a.name,
2095 (_b = this.schema.getMutationType()) === null || _b === void 0 ? void 0 : _b.name,
2096 (_c = this.schema.getSubscriptionType()) === null || _c === void 0 ? void 0 : _c.name,
2097 ].includes(typeName);
2098 const fieldsContent = node.fields.map((f) => f(node.name));
2099 if (!isRootType) {
2100 fieldsContent.push(indent(`${this.config.internalResolversPrefix}isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>${this.getPunctuation(declarationKind)}`));
2101 }
2102 const block = new DeclarationBlock(this._declarationBlockConfig)
2103 .export()
2104 .asKind(declarationKind)
2105 .withName(name, `<ContextType = ${this.config.contextType.type}, ${this.transformParentGenericType(parentType)}>`)
2106 .withBlock(fieldsContent.join('\n'));
2107 this._collectedResolvers[node.name] = name + '<ContextType>';
2108 return block.string;
2109 }
2110 UnionTypeDefinition(node, key, parent) {
2111 const declarationKind = 'type';
2112 const name = this.convertName(node, {
2113 suffix: this.config.resolverTypeSuffix,
2114 });
2115 const originalNode = parent[key];
2116 const possibleTypes = originalNode.types
2117 .map(node => node.name.value)
2118 .map(f => `'${f}'`)
2119 .join(' | ');
2120 this._collectedResolvers[node.name] = name + '<ContextType>';
2121 const parentType = this.getParentTypeToUse(node.name);
2122 return new DeclarationBlock(this._declarationBlockConfig)
2123 .export()
2124 .asKind(declarationKind)
2125 .withName(name, `<ContextType = ${this.config.contextType.type}, ${this.transformParentGenericType(parentType)}>`)
2126 .withBlock(indent(`${this.config.internalResolversPrefix}resolveType${this.config.optionalResolveType ? '?' : ''}: TypeResolveFn<${possibleTypes}, ParentType, ContextType>${this.getPunctuation(declarationKind)}`)).string;
2127 }
2128 ScalarTypeDefinition(node) {
2129 const nameAsString = node.name;
2130 const baseName = this.getTypeToUse(nameAsString);
2131 if (this._federation.skipScalar(nameAsString)) {
2132 return null;
2133 }
2134 this._hasScalars = true;
2135 this._collectedResolvers[node.name] = 'GraphQLScalarType';
2136 return new DeclarationBlock({
2137 ...this._declarationBlockConfig,
2138 blockTransformer(block) {
2139 return block;
2140 },
2141 })
2142 .export()
2143 .asKind('interface')
2144 .withName(this.convertName(node, {
2145 suffix: 'ScalarConfig',
2146 }), ` extends GraphQLScalarTypeConfig<${baseName}, any>`)
2147 .withBlock(indent(`name: '${node.name}'${this.getPunctuation('interface')}`)).string;
2148 }
2149 DirectiveDefinition(node, key, parent) {
2150 if (this._federation.skipDirective(node.name)) {
2151 return null;
2152 }
2153 const directiveName = this.convertName(node, {
2154 suffix: 'DirectiveResolver',
2155 });
2156 const sourceNode = parent[key];
2157 const hasArguments = sourceNode.arguments && sourceNode.arguments.length > 0;
2158 this._collectedDirectiveResolvers[node.name] = directiveName + '<any, any, ContextType>';
2159 const directiveArgsTypeName = this.convertName(node, {
2160 suffix: 'DirectiveArgs',
2161 });
2162 return [
2163 new DeclarationBlock({
2164 ...this._declarationBlockConfig,
2165 blockTransformer(block) {
2166 return block;
2167 },
2168 })
2169 .export()
2170 .asKind('type')
2171 .withName(directiveArgsTypeName)
2172 .withContent(hasArguments
2173 ? `{\n${this._variablesTransformer.transform(sourceNode.arguments)}\n}`
2174 : '{ }').string,
2175 new DeclarationBlock({
2176 ...this._declarationBlockConfig,
2177 blockTransformer(block) {
2178 return block;
2179 },
2180 })
2181 .export()
2182 .asKind('type')
2183 .withName(directiveName, `<Result, Parent, ContextType = ${this.config.contextType.type}, Args = ${directiveArgsTypeName}>`)
2184 .withContent(`DirectiveResolverFn<Result, Parent, ContextType, Args>`).string,
2185 ].join('\n');
2186 }
2187 buildEnumResolverContentBlock(_node, _mappedEnumType) {
2188 throw new Error(`buildEnumResolverContentBlock is not implemented!`);
2189 }
2190 buildEnumResolversExplicitMappedValues(_node, _valuesMapping) {
2191 throw new Error(`buildEnumResolversExplicitMappedValues is not implemented!`);
2192 }
2193 EnumTypeDefinition(node) {
2194 const rawTypeName = node.name;
2195 // If we have enumValues set, and it's point to an external enum - we need to allow internal values resolvers
2196 // In case we have enumValues set but as explicit values, no need to to do mapping since it's already
2197 // have type validation (the original enum has been modified by base types plugin).
2198 // If we have mapper for that type - we can skip
2199 if (!this.config.mappers[rawTypeName] && !this.config.enumValues[rawTypeName]) {
2200 return null;
2201 }
2202 const name = this.convertName(node, { suffix: this.config.resolverTypeSuffix });
2203 this._collectedResolvers[rawTypeName] = name;
2204 const hasExplicitValues = this.config.enumValues[rawTypeName] && this.config.enumValues[rawTypeName].mappedValues;
2205 return new DeclarationBlock(this._declarationBlockConfig)
2206 .export()
2207 .asKind('type')
2208 .withName(name)
2209 .withContent(hasExplicitValues
2210 ? this.buildEnumResolversExplicitMappedValues(node, this.config.enumValues[rawTypeName].mappedValues)
2211 : this.buildEnumResolverContentBlock(node, this.getTypeToUse(rawTypeName))).string;
2212 }
2213 InterfaceTypeDefinition(node) {
2214 const name = this.convertName(node, {
2215 suffix: this.config.resolverTypeSuffix,
2216 });
2217 const declarationKind = 'type';
2218 const allTypesMap = this._schema.getTypeMap();
2219 const implementingTypes = [];
2220 this._collectedResolvers[node.name] = name + '<ContextType>';
2221 for (const graphqlType of Object.values(allTypesMap)) {
2222 if (graphqlType instanceof GraphQLObjectType) {
2223 const allInterfaces = graphqlType.getInterfaces();
2224 if (allInterfaces.find(int => int.name === node.name)) {
2225 implementingTypes.push(graphqlType.name);
2226 }
2227 }
2228 }
2229 const parentType = this.getParentTypeToUse(node.name);
2230 const possibleTypes = implementingTypes.map(name => `'${name}'`).join(' | ') || 'null';
2231 const fields = this.config.onlyResolveTypeForInterfaces ? [] : node.fields || [];
2232 return new DeclarationBlock(this._declarationBlockConfig)
2233 .export()
2234 .asKind(declarationKind)
2235 .withName(name, `<ContextType = ${this.config.contextType.type}, ${this.transformParentGenericType(parentType)}>`)
2236 .withBlock([
2237 indent(`${this.config.internalResolversPrefix}resolveType${this.config.optionalResolveType ? '?' : ''}: TypeResolveFn<${possibleTypes}, ParentType, ContextType>${this.getPunctuation(declarationKind)}`),
2238 ...fields.map((f) => f(node.name)),
2239 ].join('\n')).string;
2240 }
2241 SchemaDefinition() {
2242 return null;
2243 }
2244}
2245function replacePlaceholder(pattern, typename) {
2246 return pattern.replace(/\{T\}/g, typename);
2247}
2248function hasPlaceholder(pattern) {
2249 return pattern.includes('{T}');
2250}
2251
2252gqlTag.enableExperimentalFragmentVariables();
2253var DocumentMode;
2254(function (DocumentMode) {
2255 DocumentMode["graphQLTag"] = "graphQLTag";
2256 DocumentMode["documentNode"] = "documentNode";
2257 DocumentMode["documentNodeImportFragments"] = "documentNodeImportFragments";
2258 DocumentMode["external"] = "external";
2259 DocumentMode["string"] = "string";
2260})(DocumentMode || (DocumentMode = {}));
2261const EXTENSIONS_TO_REMOVE = ['.ts', '.tsx', '.js', '.jsx'];
2262class ClientSideBaseVisitor extends BaseVisitor {
2263 constructor(_schema, _fragments, rawConfig, additionalConfig, documents) {
2264 super(rawConfig, {
2265 scalars: buildScalarsFromConfig(_schema, rawConfig),
2266 dedupeOperationSuffix: getConfigValue(rawConfig.dedupeOperationSuffix, false),
2267 optimizeDocumentNode: getConfigValue(rawConfig.optimizeDocumentNode, true),
2268 omitOperationSuffix: getConfigValue(rawConfig.omitOperationSuffix, false),
2269 gqlImport: rawConfig.gqlImport || null,
2270 documentNodeImport: rawConfig.documentNodeImport || null,
2271 noExport: !!rawConfig.noExport,
2272 importOperationTypesFrom: getConfigValue(rawConfig.importOperationTypesFrom, null),
2273 operationResultSuffix: getConfigValue(rawConfig.operationResultSuffix, ''),
2274 documentVariablePrefix: getConfigValue(rawConfig.documentVariablePrefix, ''),
2275 documentVariableSuffix: getConfigValue(rawConfig.documentVariableSuffix, 'Document'),
2276 fragmentVariablePrefix: getConfigValue(rawConfig.fragmentVariablePrefix, ''),
2277 fragmentVariableSuffix: getConfigValue(rawConfig.fragmentVariableSuffix, 'FragmentDoc'),
2278 documentMode: ((rawConfig) => {
2279 if (typeof rawConfig.noGraphQLTag === 'boolean') {
2280 return rawConfig.noGraphQLTag ? DocumentMode.documentNode : DocumentMode.graphQLTag;
2281 }
2282 return getConfigValue(rawConfig.documentMode, DocumentMode.graphQLTag);
2283 })(rawConfig),
2284 importDocumentNodeExternallyFrom: getConfigValue(rawConfig.importDocumentNodeExternallyFrom, ''),
2285 pureMagicComment: getConfigValue(rawConfig.pureMagicComment, false),
2286 experimentalFragmentVariables: getConfigValue(rawConfig.experimentalFragmentVariables, false),
2287 ...additionalConfig,
2288 });
2289 this._schema = _schema;
2290 this._fragments = _fragments;
2291 this._collectedOperations = [];
2292 this._documents = [];
2293 this._additionalImports = [];
2294 this._imports = new Set();
2295 this._documents = documents;
2296 autoBind(this);
2297 }
2298 _extractFragments(document, withNested = false) {
2299 if (!document) {
2300 return [];
2301 }
2302 const names = new Set();
2303 oldVisit(document, {
2304 enter: {
2305 FragmentSpread: (node) => {
2306 names.add(node.name.value);
2307 if (withNested) {
2308 const foundFragment = this._fragments.find(f => f.name === node.name.value);
2309 if (foundFragment) {
2310 const childItems = this._extractFragments(foundFragment.node, true);
2311 if (childItems && childItems.length > 0) {
2312 for (const item of childItems) {
2313 names.add(item);
2314 }
2315 }
2316 }
2317 }
2318 },
2319 },
2320 });
2321 return Array.from(names);
2322 }
2323 _transformFragments(document) {
2324 const includeNestedFragments = this.config.documentMode === DocumentMode.documentNode ||
2325 (this.config.dedupeFragments && document.kind === 'OperationDefinition');
2326 return this._extractFragments(document, includeNestedFragments).map(document => this.getFragmentVariableName(document));
2327 }
2328 _includeFragments(fragments, nodeKind) {
2329 if (fragments && fragments.length > 0) {
2330 if (this.config.documentMode === DocumentMode.documentNode) {
2331 return this._fragments
2332 .filter(f => fragments.includes(this.getFragmentVariableName(f.name)))
2333 .map(fragment => print(fragment.node))
2334 .join('\n');
2335 }
2336 else if (this.config.documentMode === DocumentMode.documentNodeImportFragments) {
2337 return '';
2338 }
2339 else {
2340 if (this.config.dedupeFragments && nodeKind !== 'OperationDefinition') {
2341 return '';
2342 }
2343 return `${fragments.map(name => '${' + name + '}').join('\n')}`;
2344 }
2345 }
2346 return '';
2347 }
2348 _prepareDocument(documentStr) {
2349 return documentStr;
2350 }
2351 _gql(node) {
2352 const fragments = this._transformFragments(node);
2353 const doc = this._prepareDocument(`
2354 ${print(node).split('\\').join('\\\\') /* Re-escape escaped values in GraphQL syntax */}
2355 ${this._includeFragments(fragments, node.kind)}`);
2356 if (this.config.documentMode === DocumentMode.documentNode) {
2357 let gqlObj = gqlTag([doc]);
2358 if (this.config.optimizeDocumentNode) {
2359 gqlObj = optimizeDocumentNode(gqlObj);
2360 }
2361 return JSON.stringify(gqlObj);
2362 }
2363 else if (this.config.documentMode === DocumentMode.documentNodeImportFragments) {
2364 let gqlObj = gqlTag([doc]);
2365 if (this.config.optimizeDocumentNode) {
2366 gqlObj = optimizeDocumentNode(gqlObj);
2367 }
2368 if (fragments.length > 0 && (!this.config.dedupeFragments || node.kind === 'OperationDefinition')) {
2369 const definitions = [
2370 ...gqlObj.definitions.map(t => JSON.stringify(t)),
2371 ...fragments.map(name => `...${name}.definitions`),
2372 ].join();
2373 return `{"kind":"${Kind.DOCUMENT}","definitions":[${definitions}]}`;
2374 }
2375 return JSON.stringify(gqlObj);
2376 }
2377 else if (this.config.documentMode === DocumentMode.string) {
2378 return '`' + doc + '`';
2379 }
2380 const gqlImport = this._parseImport(this.config.gqlImport || 'graphql-tag');
2381 return (gqlImport.propName || 'gql') + '`' + doc + '`';
2382 }
2383 _generateFragment(fragmentDocument) {
2384 const name = this.getFragmentVariableName(fragmentDocument);
2385 const fragmentTypeSuffix = this.getFragmentSuffix(fragmentDocument);
2386 return `export const ${name} =${this.config.pureMagicComment ? ' /*#__PURE__*/' : ''} ${this._gql(fragmentDocument)}${this.getDocumentNodeSignature(this.convertName(fragmentDocument.name.value, {
2387 useTypesPrefix: true,
2388 suffix: fragmentTypeSuffix,
2389 }), this.config.experimentalFragmentVariables
2390 ? this.convertName(fragmentDocument.name.value, {
2391 suffix: fragmentTypeSuffix + 'Variables',
2392 })
2393 : 'unknown', fragmentDocument)};`;
2394 }
2395 get fragmentsGraph() {
2396 const graph = new DepGraph({ circular: true });
2397 for (const fragment of this._fragments) {
2398 if (graph.hasNode(fragment.name)) {
2399 const cachedAsString = print(graph.getNodeData(fragment.name).node);
2400 const asString = print(fragment.node);
2401 if (cachedAsString !== asString) {
2402 throw new Error(`Duplicated fragment called '${fragment.name}'!`);
2403 }
2404 }
2405 graph.addNode(fragment.name, fragment);
2406 }
2407 this._fragments.forEach(fragment => {
2408 const depends = this._extractFragments(fragment.node);
2409 if (depends && depends.length > 0) {
2410 depends.forEach(name => {
2411 graph.addDependency(fragment.name, name);
2412 });
2413 }
2414 });
2415 return graph;
2416 }
2417 get fragments() {
2418 if (this._fragments.length === 0 || this.config.documentMode === DocumentMode.external) {
2419 return '';
2420 }
2421 const graph = this.fragmentsGraph;
2422 const orderedDeps = graph.overallOrder();
2423 const localFragments = orderedDeps
2424 .filter(name => !graph.getNodeData(name).isExternal)
2425 .map(name => this._generateFragment(graph.getNodeData(name).node));
2426 return localFragments.join('\n');
2427 }
2428 _parseImport(importStr) {
2429 // This is a special case when we want to ignore importing, and just use `gql` provided from somewhere else
2430 // Plugins that uses that will need to ensure to add import/declaration for the gql identifier
2431 if (importStr === 'gql') {
2432 return {
2433 moduleName: null,
2434 propName: 'gql',
2435 };
2436 }
2437 // This is a special use case, when we don't want this plugin to manage the import statement
2438 // of the gql tag. In this case, we provide something like `Namespace.gql` and it will be used instead.
2439 if (importStr.includes('.gql')) {
2440 return {
2441 moduleName: null,
2442 propName: importStr,
2443 };
2444 }
2445 const [moduleName, propName] = importStr.split('#');
2446 return {
2447 moduleName,
2448 propName,
2449 };
2450 }
2451 _generateImport({ moduleName, propName }, varName, isTypeImport) {
2452 const typeImport = isTypeImport && this.config.useTypeImports ? 'import type' : 'import';
2453 const propAlias = propName === varName ? '' : ` as ${varName}`;
2454 if (moduleName) {
2455 return `${typeImport} ${propName ? `{ ${propName}${propAlias} }` : varName} from '${moduleName}';`;
2456 }
2457 return null;
2458 }
2459 clearExtension(path) {
2460 const extension = extname(path);
2461 if (EXTENSIONS_TO_REMOVE.includes(extension)) {
2462 return path.replace(/\.[^/.]+$/, '');
2463 }
2464 return path;
2465 }
2466 getImports(options = {}) {
2467 (this._additionalImports || []).forEach(i => this._imports.add(i));
2468 switch (this.config.documentMode) {
2469 case DocumentMode.documentNode:
2470 case DocumentMode.documentNodeImportFragments: {
2471 const documentNodeImport = this._parseImport(this.config.documentNodeImport || 'graphql#DocumentNode');
2472 const tagImport = this._generateImport(documentNodeImport, 'DocumentNode', true);
2473 if (tagImport) {
2474 this._imports.add(tagImport);
2475 }
2476 break;
2477 }
2478 case DocumentMode.graphQLTag: {
2479 const gqlImport = this._parseImport(this.config.gqlImport || 'graphql-tag');
2480 const tagImport = this._generateImport(gqlImport, 'gql', false);
2481 if (tagImport) {
2482 this._imports.add(tagImport);
2483 }
2484 break;
2485 }
2486 case DocumentMode.external: {
2487 if (this._collectedOperations.length > 0) {
2488 if (this.config.importDocumentNodeExternallyFrom === 'near-operation-file' && this._documents.length === 1) {
2489 this._imports.add(`import * as Operations from './${this.clearExtension(basename(this._documents[0].location))}';`);
2490 }
2491 else {
2492 if (!this.config.importDocumentNodeExternallyFrom) {
2493 // eslint-disable-next-line no-console
2494 console.warn('importDocumentNodeExternallyFrom must be provided if documentMode=external');
2495 }
2496 this._imports.add(`import * as Operations from '${this.clearExtension(this.config.importDocumentNodeExternallyFrom)}';`);
2497 }
2498 }
2499 break;
2500 }
2501 }
2502 if (!options.excludeFragments && !this.config.globalNamespace) {
2503 const { documentMode, fragmentImports } = this.config;
2504 if (documentMode === DocumentMode.graphQLTag ||
2505 documentMode === DocumentMode.string ||
2506 documentMode === DocumentMode.documentNodeImportFragments) {
2507 // keep track of what imports we've already generated so we don't try
2508 // to import the same identifier twice
2509 const alreadyImported = new Map();
2510 const deduplicatedImports = fragmentImports
2511 .map(fragmentImport => {
2512 const { path, identifiers } = fragmentImport.importSource;
2513 if (!alreadyImported.has(path)) {
2514 alreadyImported.set(path, new Set());
2515 }
2516 const alreadyImportedForPath = alreadyImported.get(path);
2517 const newIdentifiers = identifiers.filter(identifier => !alreadyImportedForPath.has(identifier.name));
2518 newIdentifiers.forEach(newIdentifier => alreadyImportedForPath.add(newIdentifier.name));
2519 // filter the set of identifiers in this fragment import to only
2520 // the ones we haven't already imported from this path
2521 return {
2522 ...fragmentImport,
2523 importSource: {
2524 ...fragmentImport.importSource,
2525 identifiers: newIdentifiers,
2526 },
2527 };
2528 })
2529 // remove any imports that now have no identifiers in them
2530 .filter(fragmentImport => fragmentImport.importSource.identifiers.length > 0);
2531 deduplicatedImports.forEach(fragmentImport => {
2532 if (fragmentImport.outputPath !== fragmentImport.importSource.path) {
2533 this._imports.add(generateFragmentImportStatement(fragmentImport, 'document'));
2534 }
2535 });
2536 }
2537 }
2538 return Array.from(this._imports);
2539 }
2540 buildOperation(_node, _documentVariableName, _operationType, _operationResultType, _operationVariablesTypes, _hasRequiredVariables) {
2541 return null;
2542 }
2543 getDocumentNodeSignature(_resultType, _variablesTypes, _node) {
2544 if (this.config.documentMode === DocumentMode.documentNode ||
2545 this.config.documentMode === DocumentMode.documentNodeImportFragments) {
2546 return ` as unknown as DocumentNode`;
2547 }
2548 return '';
2549 }
2550 /**
2551 * Checks if the specific operation has variables that are non-null (required), and also doesn't have default.
2552 * This is useful for deciding of `variables` should be optional or not.
2553 * @param node
2554 */
2555 checkVariablesRequirements(node) {
2556 const variables = node.variableDefinitions || [];
2557 if (variables.length === 0) {
2558 return false;
2559 }
2560 return variables.some(variableDef => variableDef.type.kind === Kind.NON_NULL_TYPE && !variableDef.defaultValue);
2561 }
2562 getOperationVariableName(node) {
2563 return this.convertName(node, {
2564 suffix: this.config.documentVariableSuffix,
2565 prefix: this.config.documentVariablePrefix,
2566 useTypesPrefix: false,
2567 });
2568 }
2569 OperationDefinition(node) {
2570 this._collectedOperations.push(node);
2571 const documentVariableName = this.getOperationVariableName(node);
2572 const operationType = pascalCase(node.operation);
2573 const operationTypeSuffix = this.getOperationSuffix(node, operationType);
2574 const operationResultType = this.convertName(node, {
2575 suffix: operationTypeSuffix + this._parsedConfig.operationResultSuffix,
2576 });
2577 const operationVariablesTypes = this.convertName(node, {
2578 suffix: operationTypeSuffix + 'Variables',
2579 });
2580 let documentString = '';
2581 if (this.config.documentMode !== DocumentMode.external) {
2582 // only generate exports for named queries
2583 if (documentVariableName !== '') {
2584 documentString = `${this.config.noExport ? '' : 'export'} const ${documentVariableName} =${this.config.pureMagicComment ? ' /*#__PURE__*/' : ''} ${this._gql(node)}${this.getDocumentNodeSignature(operationResultType, operationVariablesTypes, node)};`;
2585 }
2586 }
2587 const hasRequiredVariables = this.checkVariablesRequirements(node);
2588 const additional = this.buildOperation(node, documentVariableName, operationType, operationResultType, operationVariablesTypes, hasRequiredVariables);
2589 return [documentString, additional].filter(a => a).join('\n');
2590 }
2591}
2592
2593function isMetadataFieldName(name) {
2594 return ['__schema', '__type'].includes(name);
2595}
2596const metadataFieldMap = {
2597 __schema: SchemaMetaFieldDef,
2598 __type: TypeMetaFieldDef,
2599};
2600class SelectionSetToObject {
2601 constructor(_processor, _scalars, _schema, _convertName, _getFragmentSuffix, _loadedFragments, _config, _parentSchemaType, _selectionSet) {
2602 this._processor = _processor;
2603 this._scalars = _scalars;
2604 this._schema = _schema;
2605 this._convertName = _convertName;
2606 this._getFragmentSuffix = _getFragmentSuffix;
2607 this._loadedFragments = _loadedFragments;
2608 this._config = _config;
2609 this._parentSchemaType = _parentSchemaType;
2610 this._selectionSet = _selectionSet;
2611 this._primitiveFields = [];
2612 this._primitiveAliasedFields = [];
2613 this._linksFields = [];
2614 this._queriedForTypename = false;
2615 autoBind(this);
2616 }
2617 createNext(parentSchemaType, selectionSet) {
2618 return new SelectionSetToObject(this._processor, this._scalars, this._schema, this._convertName.bind(this), this._getFragmentSuffix.bind(this), this._loadedFragments, this._config, parentSchemaType, selectionSet);
2619 }
2620 /**
2621 * traverse the inline fragment nodes recursively for collecting the selectionSets on each type
2622 */
2623 _collectInlineFragments(parentType, nodes, types) {
2624 if (isListType(parentType) || isNonNullType(parentType)) {
2625 return this._collectInlineFragments(parentType.ofType, nodes, types);
2626 }
2627 else if (isObjectType(parentType)) {
2628 for (const node of nodes) {
2629 const typeOnSchema = node.typeCondition ? this._schema.getType(node.typeCondition.name.value) : parentType;
2630 const { fields, inlines, spreads } = separateSelectionSet(node.selectionSet.selections);
2631 const spreadsUsage = this.buildFragmentSpreadsUsage(spreads);
2632 const directives = node.directives || undefined;
2633 if (isObjectType(typeOnSchema)) {
2634 this._appendToTypeMap(types, typeOnSchema.name, fields);
2635 this._appendToTypeMap(types, typeOnSchema.name, spreadsUsage[typeOnSchema.name]);
2636 this._appendToTypeMap(types, typeOnSchema.name, directives);
2637 this._collectInlineFragments(typeOnSchema, inlines, types);
2638 }
2639 else if (isInterfaceType(typeOnSchema) && parentType.getInterfaces().includes(typeOnSchema)) {
2640 this._appendToTypeMap(types, parentType.name, fields);
2641 this._appendToTypeMap(types, parentType.name, spreadsUsage[parentType.name]);
2642 this._collectInlineFragments(typeOnSchema, inlines, types);
2643 }
2644 }
2645 }
2646 else if (isInterfaceType(parentType)) {
2647 const possibleTypes = getPossibleTypes(this._schema, parentType);
2648 for (const node of nodes) {
2649 const schemaType = node.typeCondition ? this._schema.getType(node.typeCondition.name.value) : parentType;
2650 const { fields, inlines, spreads } = separateSelectionSet(node.selectionSet.selections);
2651 const spreadsUsage = this.buildFragmentSpreadsUsage(spreads);
2652 if (isObjectType(schemaType) && possibleTypes.find(possibleType => possibleType.name === schemaType.name)) {
2653 this._appendToTypeMap(types, schemaType.name, fields);
2654 this._appendToTypeMap(types, schemaType.name, spreadsUsage[schemaType.name]);
2655 this._collectInlineFragments(schemaType, inlines, types);
2656 }
2657 else if (isInterfaceType(schemaType) && schemaType.name === parentType.name) {
2658 for (const possibleType of possibleTypes) {
2659 this._appendToTypeMap(types, possibleType.name, fields);
2660 this._appendToTypeMap(types, possibleType.name, spreadsUsage[possibleType.name]);
2661 this._collectInlineFragments(schemaType, inlines, types);
2662 }
2663 }
2664 else {
2665 // it must be an interface type that is spread on an interface field
2666 for (const possibleType of possibleTypes) {
2667 if (!node.typeCondition) {
2668 throw new Error('Invalid state. Expected type condition for interface spread on a interface field.');
2669 }
2670 const fragmentSpreadType = this._schema.getType(node.typeCondition.name.value);
2671 // the field should only be added to the valid selections
2672 // in case the possible type actually implements the given interface
2673 if (isTypeSubTypeOf(this._schema, possibleType, fragmentSpreadType)) {
2674 this._appendToTypeMap(types, possibleType.name, fields);
2675 this._appendToTypeMap(types, possibleType.name, spreadsUsage[possibleType.name]);
2676 }
2677 }
2678 }
2679 }
2680 }
2681 else if (isUnionType(parentType)) {
2682 const possibleTypes = parentType.getTypes();
2683 for (const node of nodes) {
2684 const schemaType = node.typeCondition ? this._schema.getType(node.typeCondition.name.value) : parentType;
2685 const { fields, inlines, spreads } = separateSelectionSet(node.selectionSet.selections);
2686 const spreadsUsage = this.buildFragmentSpreadsUsage(spreads);
2687 if (isObjectType(schemaType) && possibleTypes.find(possibleType => possibleType.name === schemaType.name)) {
2688 this._appendToTypeMap(types, schemaType.name, fields);
2689 this._appendToTypeMap(types, schemaType.name, spreadsUsage[schemaType.name]);
2690 this._collectInlineFragments(schemaType, inlines, types);
2691 }
2692 else if (isInterfaceType(schemaType)) {
2693 const possibleInterfaceTypes = getPossibleTypes(this._schema, schemaType);
2694 for (const possibleType of possibleTypes) {
2695 if (possibleInterfaceTypes.find(possibleInterfaceType => possibleInterfaceType.name === possibleType.name)) {
2696 this._appendToTypeMap(types, possibleType.name, fields);
2697 this._appendToTypeMap(types, possibleType.name, spreadsUsage[possibleType.name]);
2698 this._collectInlineFragments(schemaType, inlines, types);
2699 }
2700 }
2701 }
2702 else {
2703 for (const possibleType of possibleTypes) {
2704 this._appendToTypeMap(types, possibleType.name, fields);
2705 this._appendToTypeMap(types, possibleType.name, spreadsUsage[possibleType.name]);
2706 }
2707 }
2708 }
2709 }
2710 }
2711 _createInlineFragmentForFieldNodes(parentType, fieldNodes) {
2712 return {
2713 kind: Kind.INLINE_FRAGMENT,
2714 typeCondition: {
2715 kind: Kind.NAMED_TYPE,
2716 name: {
2717 kind: Kind.NAME,
2718 value: parentType.name,
2719 },
2720 },
2721 directives: [],
2722 selectionSet: {
2723 kind: Kind.SELECTION_SET,
2724 selections: fieldNodes,
2725 },
2726 };
2727 }
2728 buildFragmentSpreadsUsage(spreads) {
2729 const selectionNodesByTypeName = {};
2730 for (const spread of spreads) {
2731 const fragmentSpreadObject = this._loadedFragments.find(lf => lf.name === spread.name.value);
2732 if (fragmentSpreadObject) {
2733 const schemaType = this._schema.getType(fragmentSpreadObject.onType);
2734 const possibleTypesForFragment = getPossibleTypes(this._schema, schemaType);
2735 for (const possibleType of possibleTypesForFragment) {
2736 const fragmentSuffix = this._getFragmentSuffix(spread.name.value);
2737 const usage = this.buildFragmentTypeName(spread.name.value, fragmentSuffix, possibleTypesForFragment.length === 1 ? null : possibleType.name);
2738 if (!selectionNodesByTypeName[possibleType.name]) {
2739 selectionNodesByTypeName[possibleType.name] = [];
2740 }
2741 selectionNodesByTypeName[possibleType.name].push({
2742 fragmentName: spread.name.value,
2743 typeName: usage,
2744 onType: fragmentSpreadObject.onType,
2745 selectionNodes: [...fragmentSpreadObject.node.selectionSet.selections],
2746 });
2747 }
2748 }
2749 }
2750 return selectionNodesByTypeName;
2751 }
2752 flattenSelectionSet(selections) {
2753 const selectionNodesByTypeName = new Map();
2754 const inlineFragmentSelections = [];
2755 const fieldNodes = [];
2756 const fragmentSpreads = [];
2757 for (const selection of selections) {
2758 switch (selection.kind) {
2759 case Kind.FIELD:
2760 fieldNodes.push(selection);
2761 break;
2762 case Kind.INLINE_FRAGMENT:
2763 inlineFragmentSelections.push(selection);
2764 break;
2765 case Kind.FRAGMENT_SPREAD:
2766 fragmentSpreads.push(selection);
2767 break;
2768 }
2769 }
2770 if (fieldNodes.length) {
2771 inlineFragmentSelections.push(this._createInlineFragmentForFieldNodes(this._parentSchemaType, fieldNodes));
2772 }
2773 this._collectInlineFragments(this._parentSchemaType, inlineFragmentSelections, selectionNodesByTypeName);
2774 const fragmentsUsage = this.buildFragmentSpreadsUsage(fragmentSpreads);
2775 for (const [typeName, records] of Object.entries(fragmentsUsage)) {
2776 this._appendToTypeMap(selectionNodesByTypeName, typeName, records);
2777 }
2778 return selectionNodesByTypeName;
2779 }
2780 _appendToTypeMap(types, typeName, nodes) {
2781 if (!types.has(typeName)) {
2782 types.set(typeName, []);
2783 }
2784 if (nodes && nodes.length > 0) {
2785 types.get(typeName).push(...nodes);
2786 }
2787 }
2788 /**
2789 * mustAddEmptyObject indicates that not all possible types on a union or interface field are covered.
2790 */
2791 _buildGroupedSelections() {
2792 if (!this._selectionSet || !this._selectionSet.selections || this._selectionSet.selections.length === 0) {
2793 return { grouped: {}, mustAddEmptyObject: true };
2794 }
2795 const selectionNodesByTypeName = this.flattenSelectionSet(this._selectionSet.selections);
2796 // in case there is not a selection for each type, we need to add a empty type.
2797 let mustAddEmptyObject = false;
2798 const possibleTypes = getPossibleTypes(this._schema, this._parentSchemaType);
2799 if (!this._config.mergeFragmentTypes || this._config.inlineFragmentTypes === 'mask') {
2800 const grouped = possibleTypes.reduce((prev, type) => {
2801 const typeName = type.name;
2802 const schemaType = this._schema.getType(typeName);
2803 if (!isObjectType(schemaType)) {
2804 throw new TypeError(`Invalid state! Schema type ${typeName} is not a valid GraphQL object!`);
2805 }
2806 const selectionNodes = selectionNodesByTypeName.get(typeName) || [];
2807 if (!prev[typeName]) {
2808 prev[typeName] = [];
2809 }
2810 const { fields } = this.buildSelectionSet(schemaType, selectionNodes);
2811 const transformedSet = this.selectionSetStringFromFields(fields);
2812 if (transformedSet) {
2813 prev[typeName].push(transformedSet);
2814 }
2815 else {
2816 mustAddEmptyObject = true;
2817 }
2818 return prev;
2819 }, {});
2820 return { grouped, mustAddEmptyObject };
2821 }
2822 else {
2823 // Accumulate a map of selected fields to the typenames that
2824 // share the exact same selected fields. When we find multiple
2825 // typenames with the same set of fields, we can collapse the
2826 // generated type to the selected fields and a string literal
2827 // union of the typenames.
2828 //
2829 // E.g. {
2830 // __typename: "foo" | "bar";
2831 // shared: string;
2832 // }
2833 const grouped = possibleTypes.reduce((prev, type) => {
2834 var _a, _b;
2835 const typeName = type.name;
2836 const schemaType = this._schema.getType(typeName);
2837 if (!isObjectType(schemaType)) {
2838 throw new TypeError(`Invalid state! Schema type ${typeName} is not a valid GraphQL object!`);
2839 }
2840 const selectionNodes = selectionNodesByTypeName.get(typeName) || [];
2841 const { typeInfo, fields } = this.buildSelectionSet(schemaType, selectionNodes);
2842 const key = this.selectionSetStringFromFields(fields);
2843 prev[key] = {
2844 fields,
2845 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),
2846 };
2847 return prev;
2848 }, {});
2849 // For every distinct set of fields, create the corresponding
2850 // string literal union of typenames.
2851 const compacted = Object.keys(grouped).reduce((acc, key) => {
2852 const typeNames = grouped[key].types.map(t => t.type);
2853 // Don't create very large string literal unions. TypeScript
2854 // will stop comparing some nested union types types when
2855 // they contain props with more than some number of string
2856 // literal union members (testing with TS 4.5 stops working
2857 // at 25 for a naive test case:
2858 // https://www.typescriptlang.org/play?ts=4.5.4&ssl=29&ssc=10&pln=29&pc=1#code/C4TwDgpgBAKg9nAMgQwE4HNoF4BQV9QA+UA3ngRQJYB21EqAXDsQEQCMLzULATJ6wGZ+3ACzCWAVnEA2cQHZxADnEBOcWwAM6jl3Z9dbIQbEGpB2QYUHlBtbp5b7O1j30ujLky7Os4wABb0nAC+ODigkFAAQlBYUOT4xGQUVLT0TKzO3G7cHqLiPtwWrFasNqx2mY6ZWXrqeexe3GyF7MXNpc3lzZXZ1dm1ruI8DTxNvGahFEkJKTR0jLMpRNx+gaicy6E4APQ7AALAAM4AtJTo1HCoEDgANhDAUMgMsAgoGNikwQDcdw9QACMXjE4shfmEItAAGI0bCzGbLfDzdIGYbiBrjVrtFidFjdFi9dj9di1Ng5dgNNjjFrqbFsXFsfFsQkOYaDckjYbjNZBHDbPaHU7nS7XP6PZBsF4wuixL6-e6PAGS6KyiXfIA
2859 const max_types = 20;
2860 for (let i = 0; i < typeNames.length; i += max_types) {
2861 const selectedTypes = typeNames.slice(i, i + max_types);
2862 const typenameUnion = grouped[key].types[0].name
2863 ? this._processor.transformTypenameField(selectedTypes.join(' | '), grouped[key].types[0].name)
2864 : [];
2865 const transformedSet = this.selectionSetStringFromFields([...typenameUnion, ...grouped[key].fields]);
2866 // The keys here will be used to generate intermediary
2867 // fragment names. To avoid blowing up the type name on large
2868 // unions, calculate a stable hash here instead.
2869 //
2870 // Also use fragment hashing if skipTypename is true, since we
2871 // then don't have a typename for naming the fragment.
2872 acc[selectedTypes.length <= 3
2873 ? selectedTypes.join('_')
2874 : createHash('sha256')
2875 .update(selectedTypes.join() || transformedSet || '')
2876 .digest('base64')] = [transformedSet];
2877 }
2878 return acc;
2879 }, {});
2880 return { grouped: compacted, mustAddEmptyObject };
2881 }
2882 }
2883 selectionSetStringFromFields(fields) {
2884 const allStrings = fields.filter((f) => typeof f === 'string');
2885 const allObjects = fields
2886 .filter((f) => typeof f !== 'string')
2887 .map(t => `${t.name}: ${t.type}`);
2888 const mergedObjects = allObjects.length ? this._processor.buildFieldsIntoObject(allObjects) : null;
2889 const transformedSet = this._processor.buildSelectionSetFromStrings([...allStrings, mergedObjects].filter(Boolean));
2890 return transformedSet;
2891 }
2892 buildSelectionSet(parentSchemaType, selectionNodes) {
2893 var _a, _b, _c;
2894 const primitiveFields = new Map();
2895 const primitiveAliasFields = new Map();
2896 const linkFieldSelectionSets = new Map();
2897 let requireTypename = false;
2898 // usages via fragment typescript type
2899 const fragmentsSpreadUsages = [];
2900 // ensure we mutate no function params
2901 selectionNodes = [...selectionNodes];
2902 let inlineFragmentConditional = false;
2903 for (const selectionNode of selectionNodes) {
2904 if ('kind' in selectionNode) {
2905 if (selectionNode.kind === 'Field') {
2906 if (!selectionNode.selectionSet) {
2907 if (selectionNode.alias) {
2908 primitiveAliasFields.set(selectionNode.alias.value, selectionNode);
2909 }
2910 else if (selectionNode.name.value === '__typename') {
2911 requireTypename = true;
2912 }
2913 else {
2914 primitiveFields.set(selectionNode.name.value, selectionNode);
2915 }
2916 }
2917 else {
2918 let selectedField = null;
2919 const fields = parentSchemaType.getFields();
2920 selectedField = fields[selectionNode.name.value];
2921 if (isMetadataFieldName(selectionNode.name.value)) {
2922 selectedField = metadataFieldMap[selectionNode.name.value];
2923 }
2924 if (!selectedField) {
2925 continue;
2926 }
2927 const fieldName = getFieldNodeNameValue(selectionNode);
2928 let linkFieldNode = linkFieldSelectionSets.get(fieldName);
2929 if (!linkFieldNode) {
2930 linkFieldNode = {
2931 selectedFieldType: selectedField.type,
2932 field: selectionNode,
2933 };
2934 }
2935 else {
2936 linkFieldNode = {
2937 ...linkFieldNode,
2938 field: {
2939 ...linkFieldNode.field,
2940 selectionSet: mergeSelectionSets(linkFieldNode.field.selectionSet, selectionNode.selectionSet),
2941 },
2942 };
2943 }
2944 linkFieldSelectionSets.set(fieldName, linkFieldNode);
2945 }
2946 }
2947 else if (selectionNode.kind === 'Directive') {
2948 if (['skip', 'include'].includes((_a = selectionNode === null || selectionNode === void 0 ? void 0 : selectionNode.name) === null || _a === void 0 ? void 0 : _a.value)) {
2949 inlineFragmentConditional = true;
2950 }
2951 }
2952 else {
2953 throw new TypeError('Unexpected type.');
2954 }
2955 continue;
2956 }
2957 if (this._config.inlineFragmentTypes === 'combine' || this._config.inlineFragmentTypes === 'mask') {
2958 fragmentsSpreadUsages.push(selectionNode.typeName);
2959 continue;
2960 }
2961 // Handle Fragment Spreads by generating inline types.
2962 const fragmentType = this._schema.getType(selectionNode.onType);
2963 if (fragmentType == null) {
2964 throw new TypeError(`Unexpected error: Type ${selectionNode.onType} does not exist within schema.`);
2965 }
2966 if (parentSchemaType.name === selectionNode.onType ||
2967 parentSchemaType.getInterfaces().find(iinterface => iinterface.name === selectionNode.onType) != null ||
2968 (isUnionType(fragmentType) &&
2969 fragmentType.getTypes().find(objectType => objectType.name === parentSchemaType.name))) {
2970 // also process fields from fragment that apply for this parentType
2971 const flatten = this.flattenSelectionSet(selectionNode.selectionNodes);
2972 const typeNodes = (_b = flatten.get(parentSchemaType.name)) !== null && _b !== void 0 ? _b : [];
2973 selectionNodes.push(...typeNodes);
2974 for (const iinterface of parentSchemaType.getInterfaces()) {
2975 const typeNodes = (_c = flatten.get(iinterface.name)) !== null && _c !== void 0 ? _c : [];
2976 selectionNodes.push(...typeNodes);
2977 }
2978 }
2979 }
2980 const linkFields = [];
2981 for (const { field, selectedFieldType } of linkFieldSelectionSets.values()) {
2982 const realSelectedFieldType = getBaseType(selectedFieldType);
2983 const selectionSet = this.createNext(realSelectedFieldType, field.selectionSet);
2984 const isConditional = hasConditionalDirectives(field) || inlineFragmentConditional;
2985 linkFields.push({
2986 alias: field.alias ? this._processor.config.formatNamedField(field.alias.value, selectedFieldType) : undefined,
2987 name: this._processor.config.formatNamedField(field.name.value, selectedFieldType, isConditional),
2988 type: realSelectedFieldType.name,
2989 selectionSet: this._processor.config.wrapTypeWithModifiers(selectionSet.transformSelectionSet().split(`\n`).join(`\n `), selectedFieldType),
2990 });
2991 }
2992 const typeInfoField = this.buildTypeNameField(parentSchemaType, this._config.nonOptionalTypename, this._config.addTypename, requireTypename, this._config.skipTypeNameForRoot);
2993 const transformed = [
2994 // Only add the typename field if we're not merging fragment
2995 // types. If we are merging, we need to wait until we know all
2996 // the involved typenames.
2997 ...(typeInfoField && (!this._config.mergeFragmentTypes || this._config.inlineFragmentTypes === 'mask')
2998 ? this._processor.transformTypenameField(typeInfoField.type, typeInfoField.name)
2999 : []),
3000 ...this._processor.transformPrimitiveFields(parentSchemaType, Array.from(primitiveFields.values()).map(field => ({
3001 isConditional: hasConditionalDirectives(field),
3002 fieldName: field.name.value,
3003 }))),
3004 ...this._processor.transformAliasesPrimitiveFields(parentSchemaType, Array.from(primitiveAliasFields.values()).map(field => ({
3005 alias: field.alias.value,
3006 fieldName: field.name.value,
3007 }))),
3008 ...this._processor.transformLinkFields(linkFields),
3009 ].filter(Boolean);
3010 const allStrings = transformed.filter(t => typeof t === 'string');
3011 const allObjectsMerged = transformed
3012 .filter(t => typeof t !== 'string')
3013 .map((t) => `${t.name}: ${t.type}`);
3014 let mergedObjectsAsString = null;
3015 if (allObjectsMerged.length > 0) {
3016 mergedObjectsAsString = this._processor.buildFieldsIntoObject(allObjectsMerged);
3017 }
3018 const fields = [...allStrings, mergedObjectsAsString].filter(Boolean);
3019 if (fragmentsSpreadUsages.length) {
3020 if (this._config.inlineFragmentTypes === 'combine') {
3021 fields.push(...fragmentsSpreadUsages);
3022 }
3023 else if (this._config.inlineFragmentTypes === 'mask') {
3024 fields.push(`{ ' $fragmentRefs': { ${fragmentsSpreadUsages.map(name => `'${name}': ${name}`).join(`;`)} } }`);
3025 }
3026 }
3027 return { typeInfo: typeInfoField, fields };
3028 }
3029 buildTypeNameField(type, nonOptionalTypename = this._config.nonOptionalTypename, addTypename = this._config.addTypename, queriedForTypename = this._queriedForTypename, skipTypeNameForRoot = this._config.skipTypeNameForRoot) {
3030 const rootTypes = getRootTypes(this._schema);
3031 if (rootTypes.has(type) && skipTypeNameForRoot && !queriedForTypename) {
3032 return null;
3033 }
3034 if (nonOptionalTypename || addTypename || queriedForTypename) {
3035 const optionalTypename = !queriedForTypename && !nonOptionalTypename;
3036 return {
3037 name: `${this._processor.config.formatNamedField('__typename')}${optionalTypename ? '?' : ''}`,
3038 type: `'${type.name}'`,
3039 };
3040 }
3041 return null;
3042 }
3043 getUnknownType() {
3044 return 'never';
3045 }
3046 getEmptyObjectType() {
3047 return `{}`;
3048 }
3049 getEmptyObjectTypeString(mustAddEmptyObject) {
3050 return mustAddEmptyObject ? ' | ' + this.getEmptyObjectType() : ``;
3051 }
3052 transformSelectionSet() {
3053 const { grouped, mustAddEmptyObject } = this._buildGroupedSelections();
3054 // This might happen in case we have an interface, that is being queries, without any GraphQL
3055 // "type" that implements it. It will lead to a runtime error, but we aim to try to reflect that in
3056 // build time as well.
3057 if (Object.keys(grouped).length === 0) {
3058 return this.getUnknownType();
3059 }
3060 return (Object.keys(grouped)
3061 .map(typeName => {
3062 const relevant = grouped[typeName].filter(Boolean);
3063 if (relevant.length === 0) {
3064 return null;
3065 }
3066 else if (relevant.length === 1) {
3067 return relevant[0];
3068 }
3069 else {
3070 return `( ${relevant.join(' & ')} )`;
3071 }
3072 })
3073 .filter(Boolean)
3074 .join(' | ') + this.getEmptyObjectTypeString(mustAddEmptyObject));
3075 }
3076 transformFragmentSelectionSetToTypes(fragmentName, fragmentSuffix, declarationBlockConfig) {
3077 const { grouped } = this._buildGroupedSelections();
3078 const subTypes = Object.keys(grouped)
3079 .map(typeName => {
3080 const possibleFields = grouped[typeName].filter(Boolean);
3081 const declarationName = this.buildFragmentTypeName(fragmentName, fragmentSuffix, typeName);
3082 if (possibleFields.length === 0) {
3083 if (!this._config.addTypename) {
3084 return { name: declarationName, content: this.getEmptyObjectType() };
3085 }
3086 return null;
3087 }
3088 return { name: declarationName, content: possibleFields.join(' & ') };
3089 })
3090 .filter(Boolean);
3091 const fragmentTypeName = this.buildFragmentTypeName(fragmentName, fragmentSuffix);
3092 const fragmentMaskPartial = this._config.inlineFragmentTypes === 'mask' ? ` & { ' $fragmentName': '${fragmentTypeName}' }` : '';
3093 if (subTypes.length === 1) {
3094 return new DeclarationBlock(declarationBlockConfig)
3095 .export()
3096 .asKind('type')
3097 .withName(fragmentTypeName)
3098 .withContent(subTypes[0].content + fragmentMaskPartial).string;
3099 }
3100 return [
3101 ...subTypes.map(t => new DeclarationBlock(declarationBlockConfig)
3102 .export(this._config.exportFragmentSpreadSubTypes)
3103 .asKind('type')
3104 .withName(t.name)
3105 .withContent(`${t.content}${this._config.inlineFragmentTypes === 'mask' ? ` & { ' $fragmentName': '${t.name}' }` : ''}`).string),
3106 new DeclarationBlock(declarationBlockConfig)
3107 .export()
3108 .asKind('type')
3109 .withName(fragmentTypeName)
3110 .withContent(subTypes.map(t => t.name).join(' | ')).string,
3111 ].join('\n');
3112 }
3113 buildFragmentTypeName(name, suffix, typeName = '') {
3114 return this._convertName(name, {
3115 useTypesPrefix: true,
3116 suffix: typeName ? `_${typeName}_${suffix}` : suffix,
3117 });
3118 }
3119}
3120
3121class BaseSelectionSetProcessor {
3122 constructor(config) {
3123 this.config = config;
3124 }
3125 buildFieldsIntoObject(allObjectsMerged) {
3126 return `{ ${allObjectsMerged.join(', ')} }`;
3127 }
3128 buildSelectionSetFromStrings(pieces) {
3129 if (pieces.length === 0) {
3130 return null;
3131 }
3132 else if (pieces.length === 1) {
3133 return pieces[0];
3134 }
3135 else {
3136 return `(\n ${pieces.join(`\n & `)}\n)`;
3137 }
3138 }
3139 transformPrimitiveFields(_schemaType, _fields) {
3140 throw new Error(`Please override "transformPrimitiveFields" as part of your BaseSelectionSetProcessor implementation!`);
3141 }
3142 transformAliasesPrimitiveFields(_schemaType, _fields) {
3143 throw new Error(`Please override "transformAliasesPrimitiveFields" as part of your BaseSelectionSetProcessor implementation!`);
3144 }
3145 transformLinkFields(_fields) {
3146 throw new Error(`Please override "transformLinkFields" as part of your BaseSelectionSetProcessor implementation!`);
3147 }
3148 transformTypenameField(_type, _name) {
3149 throw new Error(`Please override "transformTypenameField" as part of your BaseSelectionSetProcessor implementation!`);
3150 }
3151}
3152
3153class PreResolveTypesProcessor extends BaseSelectionSetProcessor {
3154 transformTypenameField(type, name) {
3155 return [
3156 {
3157 type,
3158 name,
3159 },
3160 ];
3161 }
3162 transformPrimitiveFields(schemaType, fields) {
3163 if (fields.length === 0) {
3164 return [];
3165 }
3166 return fields.map(field => {
3167 const fieldObj = schemaType.getFields()[field.fieldName];
3168 const baseType = getBaseType(fieldObj.type);
3169 let typeToUse = baseType.name;
3170 const useInnerType = field.isConditional && isNonNullType(fieldObj.type);
3171 const innerType = useInnerType ? removeNonNullWrapper(fieldObj.type) : undefined;
3172 if (isEnumType(baseType)) {
3173 typeToUse =
3174 (this.config.namespacedImportName ? `${this.config.namespacedImportName}.` : '') +
3175 this.config.convertName(baseType.name, { useTypesPrefix: this.config.enumPrefix });
3176 }
3177 else if (this.config.scalars[baseType.name]) {
3178 typeToUse = this.config.scalars[baseType.name];
3179 }
3180 const name = this.config.formatNamedField(field.fieldName, useInnerType ? innerType : fieldObj.type, field.isConditional);
3181 const wrappedType = this.config.wrapTypeWithModifiers(typeToUse, fieldObj.type);
3182 return {
3183 name,
3184 type: wrappedType,
3185 };
3186 });
3187 }
3188 transformAliasesPrimitiveFields(schemaType, fields) {
3189 if (fields.length === 0) {
3190 return [];
3191 }
3192 return fields.map(aliasedField => {
3193 if (aliasedField.fieldName === '__typename') {
3194 const name = this.config.formatNamedField(aliasedField.alias, null);
3195 return {
3196 name,
3197 type: `'${schemaType.name}'`,
3198 };
3199 }
3200 else {
3201 const fieldObj = schemaType.getFields()[aliasedField.fieldName];
3202 const baseType = getBaseType(fieldObj.type);
3203 let typeToUse = this.config.scalars[baseType.name] || baseType.name;
3204 if (isEnumType(baseType)) {
3205 typeToUse =
3206 (this.config.namespacedImportName ? `${this.config.namespacedImportName}.` : '') +
3207 this.config.convertName(baseType.name, { useTypesPrefix: this.config.enumPrefix });
3208 }
3209 const name = this.config.formatNamedField(aliasedField.alias, fieldObj.type);
3210 const wrappedType = this.config.wrapTypeWithModifiers(typeToUse, fieldObj.type);
3211 return {
3212 name,
3213 type: wrappedType,
3214 };
3215 }
3216 });
3217 }
3218 transformLinkFields(fields) {
3219 if (fields.length === 0) {
3220 return [];
3221 }
3222 return fields.map(field => ({
3223 name: field.alias || field.name,
3224 type: field.selectionSet,
3225 }));
3226 }
3227}
3228
3229function optimizeOperations(schema, documents, options) {
3230 const newDocuments = optimizeDocuments(schema, documents.map(s => s.document), options);
3231 return newDocuments.map((document, index) => {
3232 var _a;
3233 return ({
3234 location: ((_a = documents[index]) === null || _a === void 0 ? void 0 : _a.location) || 'optimized by relay',
3235 document,
3236 });
3237 });
3238}
3239
3240export { BaseDocumentsVisitor, BaseResolversVisitor, BaseSelectionSetProcessor, BaseTypesVisitor, BaseVisitor, ClientSideBaseVisitor, DEFAULT_AVOID_OPTIONALS, DEFAULT_DECLARATION_KINDS, DEFAULT_SCALARS, DeclarationBlock, DocumentMode, OMIT_TYPE, OperationVariablesToObject, PreResolveTypesProcessor, REQUIRE_FIELDS_TYPE, SelectionSetToObject, block, breakLine, buildMapperImport, buildScalars, buildScalarsFromConfig, clearExtension, convertFactory, convertNameParts, fixLocalFilePath, generateFragmentImportStatement, generateImportStatement, getBaseTypeNode, getConfigValue, getFieldNodeNameValue, getPossibleTypes, getRootTypeNames, hasConditionalDirectives, indent, indentMultiline, isExternalMapper, isExternalMapperType, mergeSelectionSets, normalizeAvoidOptionals, normalizeDeclarationKind, optimizeOperations, parseEnumValues, parseMapper, quoteIfNeeded, removeDescription, resolveImportSource, resolveRelativeImport, separateSelectionSet, stripMapperTypeInterpolation, transformComment, transformDirectiveArgumentAndInputFieldMappings, transformMappers, wrapTypeNodeWithModifiers, wrapTypeWithModifiers, wrapWithSingleQuotes };