UNPKG

117 kBJavaScriptView Raw
1import { Kind, isScalarType, isEqualType, isListType, isNonNullType, isObjectType, isAbstractType, isEnumType, isInterfaceType, GraphQLObjectType, isUnionType, visit, print, SchemaMetaFieldDef, TypeMetaFieldDef } from 'graphql';
2import { resolveExternalModuleAndFn, DetailedError, ApolloFederation, getBaseType } from '@graphql-codegen/plugin-helpers';
3import { pascalCase } from 'pascal-case';
4import { resolve, relative, dirname, join, isAbsolute, extname, basename } from 'path';
5import parse from 'parse-filepath';
6import autoBind from 'auto-bind';
7import flatMap from 'array.prototype.flatmap';
8import { DepGraph } from 'dependency-graph';
9import gqlTag from 'graphql-tag';
10import { optimizeDocuments } from '@graphql-tools/relay-operation-optimizer';
11
12const DEFAULT_SCALARS = {
13 ID: 'string',
14 String: 'string',
15 Boolean: 'boolean',
16 Int: 'number',
17 Float: 'number',
18};
19
20function isExternalMapperType(m) {
21 return !!m.import;
22}
23var MapperKind;
24(function (MapperKind) {
25 MapperKind[MapperKind["Namespace"] = 0] = "Namespace";
26 MapperKind[MapperKind["Default"] = 1] = "Default";
27 MapperKind[MapperKind["Regular"] = 2] = "Regular";
28})(MapperKind || (MapperKind = {}));
29function prepareLegacy(mapper) {
30 const items = mapper.split('#');
31 const isNamespace = items.length === 3;
32 const isDefault = items[1].trim() === 'default' || items[1].startsWith('default ');
33 const hasAlias = items[1].includes(' as ');
34 return {
35 items,
36 isDefault,
37 isNamespace,
38 hasAlias,
39 };
40}
41function prepare(mapper) {
42 const [source, path] = mapper.split('#');
43 const isNamespace = path.includes('.');
44 const isDefault = path.trim() === 'default' || path.startsWith('default ');
45 const hasAlias = path.includes(' as ');
46 return {
47 items: isNamespace ? [source, ...path.split('.')] : [source, path],
48 isDefault,
49 isNamespace,
50 hasAlias,
51 };
52}
53function isLegacyMode(mapper) {
54 return mapper.split('#').length === 3;
55}
56function parseMapper(mapper, gqlTypeName = null, suffix) {
57 if (isExternalMapper(mapper)) {
58 const { isNamespace, isDefault, hasAlias, items } = isLegacyMode(mapper) ? prepareLegacy(mapper) : prepare(mapper);
59 const mapperKind = isNamespace
60 ? MapperKind.Namespace
61 : isDefault
62 ? MapperKind.Default
63 : MapperKind.Regular;
64 function handleAlias(isDefault = false) {
65 const [importedType, aliasType] = items[1].split(/\s+as\s+/);
66 const type = maybeSuffix(aliasType);
67 return {
68 importElement: isDefault ? type : `${importedType} as ${type}`,
69 type: type,
70 };
71 }
72 function maybeSuffix(type) {
73 if (suffix) {
74 return addSuffix(type, suffix);
75 }
76 return type;
77 }
78 function handle() {
79 switch (mapperKind) {
80 // ./my/module#Namespace#Identifier
81 case MapperKind.Namespace: {
82 const [, ns, identifier] = items;
83 return {
84 type: `${ns}.${identifier}`,
85 importElement: ns,
86 };
87 }
88 case MapperKind.Default: {
89 // ./my/module#default as alias
90 if (hasAlias) {
91 return handleAlias(true);
92 }
93 const type = maybeSuffix(`${gqlTypeName}`);
94 // ./my/module#default
95 return {
96 importElement: type,
97 type,
98 };
99 }
100 case MapperKind.Regular: {
101 // ./my/module#Identifier as alias
102 if (hasAlias) {
103 return handleAlias();
104 }
105 const identifier = items[1];
106 const type = maybeSuffix(identifier);
107 // ./my/module#Identifier
108 return {
109 type,
110 importElement: suffix ? `${identifier} as ${type}` : type,
111 };
112 }
113 }
114 }
115 const { type, importElement } = handle();
116 return {
117 default: isDefault,
118 isExternal: true,
119 source: items[0],
120 type,
121 import: importElement.replace(/<(.*?)>/g, ''),
122 };
123 }
124 return {
125 isExternal: false,
126 type: mapper,
127 };
128}
129function addSuffix(element, suffix) {
130 const generic = element.indexOf('<');
131 if (generic === -1) {
132 return `${element}${suffix}`;
133 }
134 return `${element.slice(0, generic)}${suffix}${element.slice(generic)}`;
135}
136function isExternalMapper(value) {
137 return value.includes('#') && !value.includes('"') && !value.includes("'");
138}
139function transformMappers(rawMappers, mapperTypeSuffix) {
140 const result = {};
141 Object.keys(rawMappers).forEach(gqlTypeName => {
142 const mapperDef = rawMappers[gqlTypeName];
143 const parsedMapper = parseMapper(mapperDef, gqlTypeName, mapperTypeSuffix);
144 result[gqlTypeName] = parsedMapper;
145 });
146 return result;
147}
148
149const getConfigValue = (value, defaultValue) => {
150 if (value === null || value === undefined) {
151 return defaultValue;
152 }
153 return value;
154};
155function quoteIfNeeded(array, joinWith = ' & ') {
156 if (array.length === 0) {
157 return '';
158 }
159 else if (array.length === 1) {
160 return array[0];
161 }
162 else {
163 return `(${array.join(joinWith)})`;
164 }
165}
166function block(array) {
167 return array && array.length !== 0 ? '{\n' + array.join('\n') + '\n}' : '';
168}
169function wrapWithSingleQuotes(value) {
170 if (typeof value === 'number' ||
171 (typeof value === 'string' && !isNaN(parseInt(value)) && parseFloat(value).toString() === value)) {
172 return `${value}`;
173 }
174 return `'${value}'`;
175}
176function breakLine(str) {
177 return str + '\n';
178}
179function indent(str, count = 1) {
180 return new Array(count).fill(' ').join('') + str;
181}
182function indentMultiline(str, count = 1) {
183 const indentation = new Array(count).fill(' ').join('');
184 const replaceWith = '\n' + indentation;
185 return indentation + str.replace(/\n/g, replaceWith);
186}
187function transformComment(comment, indentLevel = 0) {
188 if (!comment || comment === '') {
189 return '';
190 }
191 if (isStringValueNode(comment)) {
192 comment = comment.value;
193 }
194 comment = comment.split('*/').join('*\\/');
195 let lines = comment.split('\n');
196 if (lines.length === 1) {
197 return indent(`/** ${lines[0]} */\n`, indentLevel);
198 }
199 lines = ['/**', ...lines.map(line => ` * ${line}`), ' */\n'];
200 return lines.map(line => indent(line, indentLevel)).join('\n');
201}
202class DeclarationBlock {
203 constructor(_config) {
204 this._config = _config;
205 this._decorator = null;
206 this._export = false;
207 this._name = null;
208 this._kind = null;
209 this._methodName = null;
210 this._content = null;
211 this._block = null;
212 this._nameGenerics = null;
213 this._comment = null;
214 this._ignoreBlockWrapper = false;
215 this._config = {
216 blockWrapper: '',
217 blockTransformer: block => block,
218 enumNameValueSeparator: ':',
219 ...this._config,
220 };
221 }
222 withDecorator(decorator) {
223 this._decorator = decorator;
224 return this;
225 }
226 export(exp = true) {
227 if (!this._config.ignoreExport) {
228 this._export = exp;
229 }
230 return this;
231 }
232 asKind(kind) {
233 this._kind = kind;
234 return this;
235 }
236 withComment(comment) {
237 const nonEmptyComment = isStringValueNode(comment) ? !!comment.value : !!comment;
238 if (nonEmptyComment) {
239 this._comment = transformComment(comment, 0);
240 }
241 return this;
242 }
243 withMethodCall(methodName, ignoreBlockWrapper = false) {
244 this._methodName = methodName;
245 this._ignoreBlockWrapper = ignoreBlockWrapper;
246 return this;
247 }
248 withBlock(block) {
249 this._block = block;
250 return this;
251 }
252 withContent(content) {
253 this._content = content;
254 return this;
255 }
256 withName(name, generics = null) {
257 this._name = name;
258 this._nameGenerics = generics;
259 return this;
260 }
261 get string() {
262 let result = '';
263 if (this._decorator) {
264 result += this._decorator + '\n';
265 }
266 if (this._export) {
267 result += 'export ';
268 }
269 if (this._kind) {
270 let extra = '';
271 let name = '';
272 if (['type', 'const', 'var', 'let'].includes(this._kind)) {
273 extra = '= ';
274 }
275 if (this._name) {
276 name = this._name + (this._nameGenerics || '') + ' ';
277 }
278 result += this._kind + ' ' + name + extra;
279 }
280 if (this._block) {
281 if (this._content) {
282 result += this._content;
283 }
284 const blockWrapper = this._ignoreBlockWrapper ? '' : this._config.blockWrapper;
285 const before = '{' + blockWrapper;
286 const after = blockWrapper + '}';
287 const block = [before, this._block, after].filter(val => !!val).join('\n');
288 if (this._methodName) {
289 result += `${this._methodName}(${this._config.blockTransformer(block)})`;
290 }
291 else {
292 result += this._config.blockTransformer(block);
293 }
294 }
295 else if (this._content) {
296 result += this._content;
297 }
298 else if (this._kind) {
299 result += this._config.blockTransformer('{}');
300 }
301 return ((this._comment ? this._comment : '') +
302 result +
303 (this._kind === 'interface' || this._kind === 'enum' || this._kind === 'namespace' || this._kind === 'function'
304 ? ''
305 : ';') +
306 '\n');
307 }
308}
309function getBaseTypeNode(typeNode) {
310 if (typeNode.kind === Kind.LIST_TYPE || typeNode.kind === Kind.NON_NULL_TYPE) {
311 return getBaseTypeNode(typeNode.type);
312 }
313 return typeNode;
314}
315function convertNameParts(str, func, removeUnderscore = false) {
316 if (removeUnderscore) {
317 return func(str);
318 }
319 return str
320 .split('_')
321 .map(s => func(s))
322 .join('_');
323}
324function buildScalars(schema, scalarsMapping, defaultScalarsMapping = DEFAULT_SCALARS, defaultScalarType = 'any') {
325 const result = {};
326 Object.keys(defaultScalarsMapping).forEach(name => {
327 result[name] = parseMapper(defaultScalarsMapping[name]);
328 });
329 if (schema) {
330 const typeMap = schema.getTypeMap();
331 Object.keys(typeMap)
332 .map(typeName => typeMap[typeName])
333 .filter(type => isScalarType(type))
334 .map((scalarType) => {
335 const name = scalarType.name;
336 if (typeof scalarsMapping === 'string') {
337 const value = parseMapper(scalarsMapping + '#' + name, name);
338 result[name] = value;
339 }
340 else if (scalarsMapping && typeof scalarsMapping[name] === 'string') {
341 const value = parseMapper(scalarsMapping[name], name);
342 result[name] = value;
343 }
344 else if (scalarsMapping && scalarsMapping[name]) {
345 result[name] = {
346 isExternal: false,
347 type: JSON.stringify(scalarsMapping[name]),
348 };
349 }
350 else if (!defaultScalarsMapping[name]) {
351 result[name] = {
352 isExternal: false,
353 type: defaultScalarType,
354 };
355 }
356 });
357 }
358 else if (scalarsMapping) {
359 if (typeof scalarsMapping === 'string') {
360 throw new Error('Cannot use string scalars mapping when building without a schema');
361 }
362 Object.keys(scalarsMapping).forEach(name => {
363 if (typeof scalarsMapping[name] === 'string') {
364 const value = parseMapper(scalarsMapping[name], name);
365 result[name] = value;
366 }
367 else {
368 result[name] = {
369 isExternal: false,
370 type: JSON.stringify(scalarsMapping[name]),
371 };
372 }
373 });
374 }
375 return result;
376}
377function isStringValueNode(node) {
378 return node && typeof node === 'object' && node.kind === Kind.STRING;
379}
380function isRootType(type, schema) {
381 return (isEqualType(type, schema.getQueryType()) ||
382 isEqualType(type, schema.getMutationType()) ||
383 isEqualType(type, schema.getSubscriptionType()));
384}
385function getRootTypeNames(schema) {
386 return [schema.getQueryType(), schema.getMutationType(), schema.getSubscriptionType()]
387 .filter(t => t)
388 .map(t => t.name);
389}
390function stripMapperTypeInterpolation(identifier) {
391 return identifier.trim().replace(/<{.*}>/, '');
392}
393const OMIT_TYPE = 'export type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;';
394const REQUIRE_FIELDS_TYPE = `export type RequireFields<T, K extends keyof T> = { [X in Exclude<keyof T, K>]?: T[X] } & { [P in K]-?: NonNullable<T[P]> };`;
395function mergeSelectionSets(selectionSet1, selectionSet2) {
396 const newSelections = [...selectionSet1.selections];
397 for (const selection2 of selectionSet2.selections) {
398 if (selection2.kind === 'FragmentSpread') {
399 newSelections.push(selection2);
400 continue;
401 }
402 if (selection2.kind !== 'Field') {
403 throw new TypeError('Invalid state.');
404 }
405 const match = newSelections.find(selection1 => selection1.kind === 'Field' && getFieldNodeNameValue(selection1) === getFieldNodeNameValue(selection2));
406 if (match) {
407 // recursively merge all selection sets
408 if (match.kind === 'Field' && match.selectionSet && selection2.selectionSet) {
409 mergeSelectionSets(match.selectionSet, selection2.selectionSet);
410 }
411 continue;
412 }
413 newSelections.push(selection2);
414 }
415 // replace existing selections
416 selectionSet1.selections = newSelections;
417}
418const getFieldNodeNameValue = (node) => {
419 return (node.alias || node.name).value;
420};
421function separateSelectionSet(selections) {
422 return {
423 fields: selections.filter(s => s.kind === Kind.FIELD),
424 inlines: selections.filter(s => s.kind === Kind.INLINE_FRAGMENT),
425 spreads: selections.filter(s => s.kind === Kind.FRAGMENT_SPREAD),
426 };
427}
428function getPossibleTypes(schema, type) {
429 if (isListType(type) || isNonNullType(type)) {
430 return getPossibleTypes(schema, type.ofType);
431 }
432 else if (isObjectType(type)) {
433 return [type];
434 }
435 else if (isAbstractType(type)) {
436 return schema.getPossibleTypes(type);
437 }
438 return [];
439}
440function wrapTypeWithModifiers(baseType, type, options) {
441 let currentType = type;
442 const modifiers = [];
443 while (currentType) {
444 if (isNonNullType(currentType)) {
445 currentType = currentType.ofType;
446 }
447 else {
448 modifiers.push(options.wrapOptional);
449 }
450 if (isListType(currentType)) {
451 modifiers.push(options.wrapArray);
452 currentType = currentType.ofType;
453 }
454 else {
455 break;
456 }
457 }
458 return modifiers.reduceRight((result, modifier) => modifier(result), baseType);
459}
460
461function getKind(node) {
462 if (typeof node === 'string') {
463 return 'typeNames';
464 }
465 if (['EnumValueDefinition', 'EnumValue'].includes(node.kind)) {
466 return 'enumValues';
467 }
468 return 'typeNames';
469}
470function getName(node) {
471 if (typeof node === 'string') {
472 return node;
473 }
474 switch (node.kind) {
475 case 'OperationDefinition':
476 case 'Variable':
477 case 'Argument':
478 case 'FragmentSpread':
479 case 'FragmentDefinition':
480 case 'ObjectField':
481 case 'Directive':
482 case 'NamedType':
483 case 'ScalarTypeDefinition':
484 case 'ObjectTypeDefinition':
485 case 'FieldDefinition':
486 case 'InputValueDefinition':
487 case 'InterfaceTypeDefinition':
488 case 'UnionTypeDefinition':
489 case 'EnumTypeDefinition':
490 case 'EnumValueDefinition':
491 case 'InputObjectTypeDefinition':
492 case 'DirectiveDefinition': {
493 return getName(node.name);
494 }
495 case 'Name': {
496 return node.value;
497 }
498 case 'Field': {
499 return getName(node.alias || node.name);
500 }
501 case 'VariableDefinition': {
502 return getName(node.variable);
503 }
504 }
505 return undefined;
506}
507function convertFactory(config) {
508 function resolveConventionName(type) {
509 if (!config.namingConvention) {
510 return (str, opts = {}) => {
511 return convertNameParts(str, pascalCase, getConfigValue((opts || {}).transformUnderscore, false));
512 };
513 }
514 if (typeof config.namingConvention === 'string') {
515 if (config.namingConvention === 'keep') {
516 return str => str;
517 }
518 return (str, opts = {}) => {
519 return convertNameParts(str, resolveExternalModuleAndFn(config.namingConvention), getConfigValue((opts || {}).transformUnderscore, false));
520 };
521 }
522 if (typeof config.namingConvention === 'function') {
523 return (str, opts = {}) => {
524 return convertNameParts(str, config.namingConvention, getConfigValue((opts || {}).transformUnderscore, false));
525 };
526 }
527 if (typeof config.namingConvention === 'object' && config.namingConvention[type] === 'keep') {
528 return str => str;
529 }
530 if (typeof config.namingConvention === 'object') {
531 if (!config.namingConvention[type]) {
532 return (str, opts = {}) => {
533 const transformUnderscore = config.namingConvention.transformUnderscore || (opts || {}).transformUnderscore;
534 return convertNameParts(str, pascalCase, getConfigValue(transformUnderscore, false));
535 };
536 }
537 return (str, opts = {}) => {
538 return convertNameParts(str, resolveExternalModuleAndFn(config.namingConvention[type]), getConfigValue((opts || {}).transformUnderscore, true));
539 };
540 }
541 return config.namingConvention[type];
542 }
543 return (node, opts) => {
544 const prefix = opts && opts.prefix;
545 const suffix = opts && opts.suffix;
546 const kind = getKind(node);
547 const str = [prefix || '', getName(node), suffix || ''].join('');
548 return resolveConventionName(kind)(str, opts);
549 };
550}
551
552function parseEnumValues(schema, mapOrStr = {}) {
553 const allTypes = schema.getTypeMap();
554 const allEnums = Object.keys(allTypes).filter(t => isEnumType(allTypes[t]));
555 if (typeof mapOrStr === 'object') {
556 for (const enumTypeName of allEnums) {
557 const enumType = schema.getType(enumTypeName);
558 for (const { name, value } of enumType.getValues()) {
559 if (value && value !== name) {
560 mapOrStr[enumTypeName] = mapOrStr[enumTypeName] || {};
561 if (typeof mapOrStr[enumTypeName] !== 'string' && !mapOrStr[enumTypeName][name]) {
562 mapOrStr[enumTypeName][name] = value;
563 }
564 }
565 }
566 }
567 const invalidMappings = Object.keys(mapOrStr).filter(gqlName => !allEnums.includes(gqlName));
568 if (invalidMappings.length > 0) {
569 throw new DetailedError(`Invalid 'enumValues' mapping!`, `The following types does not exist in your GraphQL schema: ${invalidMappings.join(', ')}`);
570 }
571 return Object.keys(mapOrStr).reduce((prev, gqlIdentifier) => {
572 const pointer = mapOrStr[gqlIdentifier];
573 if (typeof pointer === 'string') {
574 const mapper = parseMapper(pointer, gqlIdentifier);
575 return {
576 ...prev,
577 [gqlIdentifier]: {
578 isDefault: mapper.isExternal && mapper.default,
579 typeIdentifier: gqlIdentifier,
580 sourceFile: mapper.isExternal ? mapper.source : null,
581 sourceIdentifier: mapper.type,
582 importIdentifier: mapper.isExternal ? mapper.import : null,
583 mappedValues: null,
584 },
585 };
586 }
587 else if (typeof pointer === 'object') {
588 return {
589 ...prev,
590 [gqlIdentifier]: {
591 isDefault: false,
592 typeIdentifier: gqlIdentifier,
593 sourceFile: null,
594 sourceIdentifier: null,
595 importIdentifier: null,
596 mappedValues: pointer,
597 },
598 };
599 }
600 else {
601 throw new DetailedError(`Invalid "enumValues" configuration`, `Enum "${gqlIdentifier}": expected string or object (with enum values mapping)`);
602 }
603 }, {});
604 }
605 else if (typeof mapOrStr === 'string') {
606 return allEnums
607 .filter(enumName => !enumName.startsWith('__'))
608 .reduce((prev, enumName) => {
609 return {
610 ...prev,
611 [enumName]: {
612 isDefault: false,
613 typeIdentifier: enumName,
614 sourceFile: mapOrStr,
615 sourceIdentifier: enumName,
616 importIdentifier: enumName,
617 mappedValues: null,
618 },
619 };
620 }, {});
621 }
622 return {};
623}
624
625const DEFAULT_DECLARATION_KINDS = {
626 scalar: 'type',
627 input: 'type',
628 type: 'type',
629 interface: 'type',
630 arguments: 'type',
631};
632function normalizeDeclarationKind(declarationKind) {
633 if (typeof declarationKind === 'string') {
634 return {
635 scalar: declarationKind,
636 input: declarationKind,
637 type: declarationKind,
638 interface: declarationKind,
639 arguments: declarationKind,
640 };
641 }
642 return {
643 ...DEFAULT_DECLARATION_KINDS,
644 ...declarationKind,
645 };
646}
647
648const DEFAULT_AVOID_OPTIONALS = {
649 object: false,
650 inputValue: false,
651 field: false,
652};
653function normalizeAvoidOptionals(avoidOptionals) {
654 if (typeof avoidOptionals === 'boolean') {
655 return {
656 object: avoidOptionals,
657 inputValue: avoidOptionals,
658 field: avoidOptionals,
659 };
660 }
661 return {
662 ...DEFAULT_AVOID_OPTIONALS,
663 ...avoidOptionals,
664 };
665}
666
667function generateFragmentImportStatement(statement, kind) {
668 const { importSource: fragmentImportSource, ...rest } = statement;
669 const { identifiers, path, namespace } = fragmentImportSource;
670 const importSource = {
671 identifiers: identifiers
672 .filter(fragmentImport => kind === 'both' || kind === fragmentImport.kind)
673 .map(({ name }) => name),
674 path,
675 namespace,
676 };
677 return generateImportStatement({ importSource, ...rest });
678}
679function generateImportStatement(statement) {
680 const { baseDir, importSource, outputPath } = statement;
681 const importPath = resolveImportPath(baseDir, outputPath, importSource.path);
682 const importNames = importSource.identifiers && importSource.identifiers.length ? `{ ${Array.from(new Set(importSource.identifiers)).join(', ')} }` : '*';
683 const importAlias = importSource.namespace ? ` as ${importSource.namespace}` : '';
684 return `import ${importNames}${importAlias} from '${importPath}';${importAlias ? '\n' : ''}`;
685}
686function resolveImportPath(baseDir, outputPath, sourcePath) {
687 const shouldAbsolute = !sourcePath.startsWith('~');
688 if (shouldAbsolute) {
689 const absGeneratedFilePath = resolve(baseDir, outputPath);
690 const absImportFilePath = resolve(baseDir, sourcePath);
691 return resolveRelativeImport(absGeneratedFilePath, absImportFilePath);
692 }
693 else {
694 return sourcePath.replace(`~`, '');
695 }
696}
697function resolveRelativeImport(from, to) {
698 if (!isAbsolute(from)) {
699 throw new Error(`Argument 'from' must be an absolute path, '${from}' given.`);
700 }
701 if (!isAbsolute(to)) {
702 throw new Error(`Argument 'to' must be an absolute path, '${to}' given.`);
703 }
704 return fixLocalFilePath(clearExtension(relative(dirname(from), to)));
705}
706function resolveImportSource(source) {
707 return typeof source === 'string' ? { path: source } : source;
708}
709function clearExtension(path) {
710 const parsedPath = parse(path);
711 return join(parsedPath.dir, parsedPath.name).replace(/\\/g, '/');
712}
713function fixLocalFilePath(path) {
714 return !path.startsWith('..') ? `./${path}` : path;
715}
716
717class BaseVisitor {
718 constructor(rawConfig, additionalConfig) {
719 this._declarationBlockConfig = {};
720 this._parsedConfig = {
721 convert: convertFactory(rawConfig),
722 typesPrefix: rawConfig.typesPrefix || '',
723 externalFragments: rawConfig.externalFragments || [],
724 fragmentImports: rawConfig.fragmentImports || [],
725 addTypename: !rawConfig.skipTypename,
726 nonOptionalTypename: !!rawConfig.nonOptionalTypename,
727 ...(additionalConfig || {}),
728 };
729 this.scalars = {};
730 Object.keys(this.config.scalars || {}).forEach(key => {
731 this.scalars[key] = this.config.scalars[key].type;
732 });
733 autoBind(this);
734 }
735 getVisitorKindContextFromAncestors(ancestors) {
736 if (!ancestors) {
737 return [];
738 }
739 return ancestors.map(t => t.kind).filter(Boolean);
740 }
741 get config() {
742 return this._parsedConfig;
743 }
744 convertName(node, options) {
745 const useTypesPrefix = typeof (options && options.useTypesPrefix) === 'boolean' ? options.useTypesPrefix : true;
746 return (useTypesPrefix ? this.config.typesPrefix : '') + this.config.convert(node, options);
747 }
748 getOperationSuffix(node, operationType) {
749 const { omitOperationSuffix = false, dedupeOperationSuffix = false } = this.config;
750 const operationName = typeof node === 'string' ? node : node.name.value;
751 return omitOperationSuffix
752 ? ''
753 : dedupeOperationSuffix && operationName.toLowerCase().endsWith(operationType.toLowerCase())
754 ? ''
755 : operationType;
756 }
757 getFragmentSuffix(node) {
758 return this.getOperationSuffix(node, 'Fragment');
759 }
760 getFragmentName(node) {
761 return this.convertName(node, {
762 suffix: this.getFragmentSuffix(node),
763 useTypesPrefix: false,
764 });
765 }
766 getFragmentVariableName(node) {
767 const { omitOperationSuffix = false, dedupeOperationSuffix = false, fragmentVariableSuffix = 'FragmentDoc', fragmentVariablePrefix = '', } = this.config;
768 const fragmentName = typeof node === 'string' ? node : node.name.value;
769 const suffix = omitOperationSuffix
770 ? ''
771 : dedupeOperationSuffix &&
772 fragmentName.toLowerCase().endsWith('fragment') &&
773 fragmentVariableSuffix.toLowerCase().startsWith('fragment')
774 ? fragmentVariableSuffix.substring('fragment'.length)
775 : fragmentVariableSuffix;
776 return this.convertName(node, {
777 prefix: fragmentVariablePrefix,
778 suffix,
779 useTypesPrefix: false,
780 });
781 }
782 getPunctuation(declarationKind) {
783 return '';
784 }
785}
786
787class OperationVariablesToObject {
788 constructor(_scalars, _convertName, _namespacedImportName = null, _enumNames = [], _enumPrefix = true, _enumValues = {}) {
789 this._scalars = _scalars;
790 this._convertName = _convertName;
791 this._namespacedImportName = _namespacedImportName;
792 this._enumNames = _enumNames;
793 this._enumPrefix = _enumPrefix;
794 this._enumValues = _enumValues;
795 autoBind(this);
796 }
797 getName(node) {
798 if (node.name) {
799 if (typeof node.name === 'string') {
800 return node.name;
801 }
802 return node.name.value;
803 }
804 else if (node.variable) {
805 return node.variable.name.value;
806 }
807 return null;
808 }
809 transform(variablesNode) {
810 if (!variablesNode || variablesNode.length === 0) {
811 return null;
812 }
813 return (variablesNode.map(variable => indent(this.transformVariable(variable))).join(`${this.getPunctuation()}\n`) +
814 this.getPunctuation());
815 }
816 getScalar(name) {
817 const prefix = this._namespacedImportName ? `${this._namespacedImportName}.` : '';
818 return `${prefix}Scalars['${name}']`;
819 }
820 transformVariable(variable) {
821 let typeValue = null;
822 const prefix = this._namespacedImportName ? `${this._namespacedImportName}.` : '';
823 if (typeof variable.type === 'string') {
824 typeValue = variable.type;
825 }
826 else {
827 const baseType = getBaseTypeNode(variable.type);
828 const typeName = baseType.name.value;
829 if (this._scalars[typeName]) {
830 typeValue = this.getScalar(typeName);
831 }
832 else if (this._enumValues[typeName] && this._enumValues[typeName].sourceFile) {
833 typeValue = this._enumValues[typeName].typeIdentifier || this._enumValues[typeName].sourceIdentifier;
834 }
835 else {
836 typeValue = `${prefix}${this._convertName(baseType, {
837 useTypesPrefix: this._enumNames.includes(typeName) ? this._enumPrefix : true,
838 })}`;
839 }
840 }
841 const fieldName = this.getName(variable);
842 const fieldType = this.wrapAstTypeWithModifiers(typeValue, variable.type);
843 const hasDefaultValue = variable.defaultValue != null && typeof variable.defaultValue !== 'undefined';
844 const isNonNullType = variable.type.kind === Kind.NON_NULL_TYPE;
845 const formattedFieldString = this.formatFieldString(fieldName, isNonNullType, hasDefaultValue);
846 const formattedTypeString = this.formatTypeString(fieldType, isNonNullType, hasDefaultValue);
847 return `${formattedFieldString}: ${formattedTypeString}`;
848 }
849 wrapAstTypeWithModifiers(baseType, typeNode) {
850 throw new Error(`You must override "wrapAstTypeWithModifiers" of OperationVariablesToObject!`);
851 }
852 formatFieldString(fieldName, isNonNullType, hasDefaultValue) {
853 return fieldName;
854 }
855 formatTypeString(fieldType, isNonNullType, hasDefaultValue) {
856 const prefix = this._namespacedImportName ? `${this._namespacedImportName}.` : '';
857 if (hasDefaultValue) {
858 return `${prefix}Maybe<${fieldType}>`;
859 }
860 return fieldType;
861 }
862 getPunctuation() {
863 return ',';
864 }
865}
866
867class BaseTypesVisitor extends BaseVisitor {
868 constructor(_schema, rawConfig, additionalConfig, defaultScalars = DEFAULT_SCALARS) {
869 super(rawConfig, {
870 enumPrefix: getConfigValue(rawConfig.enumPrefix, true),
871 onlyOperationTypes: getConfigValue(rawConfig.onlyOperationTypes, false),
872 addUnderscoreToArgsType: getConfigValue(rawConfig.addUnderscoreToArgsType, false),
873 enumValues: parseEnumValues(_schema, rawConfig.enumValues),
874 declarationKind: normalizeDeclarationKind(rawConfig.declarationKind),
875 scalars: buildScalars(_schema, rawConfig.scalars, defaultScalars),
876 fieldWrapperValue: getConfigValue(rawConfig.fieldWrapperValue, 'T'),
877 wrapFieldDefinitions: getConfigValue(rawConfig.wrapFieldDefinitions, false),
878 ...additionalConfig,
879 });
880 this._schema = _schema;
881 this._argumentsTransformer = new OperationVariablesToObject(this.scalars, this.convertName);
882 }
883 getExportPrefix() {
884 return 'export ';
885 }
886 getFieldWrapperValue() {
887 if (this.config.fieldWrapperValue) {
888 return `${this.getExportPrefix()}type FieldWrapper<T> = ${this.config.fieldWrapperValue};`;
889 }
890 return '';
891 }
892 getScalarsImports() {
893 return Object.keys(this.config.scalars)
894 .map(enumName => {
895 const mappedValue = this.config.scalars[enumName];
896 if (mappedValue.isExternal) {
897 return this._buildTypeImport(mappedValue.import, mappedValue.source, mappedValue.default);
898 }
899 return null;
900 })
901 .filter(a => a);
902 }
903 get scalarsDefinition() {
904 const allScalars = Object.keys(this.config.scalars).map(scalarName => {
905 const scalarValue = this.config.scalars[scalarName].type;
906 const scalarType = this._schema.getType(scalarName);
907 const comment = scalarType && scalarType.astNode && scalarType.description ? transformComment(scalarType.description, 1) : '';
908 const { scalar } = this._parsedConfig.declarationKind;
909 return comment + indent(`${scalarName}: ${scalarValue}${this.getPunctuation(scalar)}`);
910 });
911 return new DeclarationBlock(this._declarationBlockConfig)
912 .export()
913 .asKind(this._parsedConfig.declarationKind.scalar)
914 .withName('Scalars')
915 .withComment('All built-in and custom scalars, mapped to their actual values')
916 .withBlock(allScalars.join('\n')).string;
917 }
918 setDeclarationBlockConfig(config) {
919 this._declarationBlockConfig = config;
920 }
921 setArgumentsTransformer(argumentsTransfomer) {
922 this._argumentsTransformer = argumentsTransfomer;
923 }
924 NonNullType(node) {
925 const asString = node.type;
926 return asString;
927 }
928 getInputObjectDeclarationBlock(node) {
929 return new DeclarationBlock(this._declarationBlockConfig)
930 .export()
931 .asKind(this._parsedConfig.declarationKind.input)
932 .withName(this.convertName(node))
933 .withComment(node.description)
934 .withBlock(node.fields.join('\n'));
935 }
936 InputObjectTypeDefinition(node) {
937 return this.getInputObjectDeclarationBlock(node).string;
938 }
939 InputValueDefinition(node) {
940 const comment = transformComment(node.description, 1);
941 const { input } = this._parsedConfig.declarationKind;
942 return comment + indent(`${node.name}: ${node.type}${this.getPunctuation(input)}`);
943 }
944 Name(node) {
945 return node.value;
946 }
947 FieldDefinition(node) {
948 const typeString = node.type;
949 const { type } = this._parsedConfig.declarationKind;
950 const comment = this.getFieldComment(node);
951 return comment + indent(`${node.name}: ${typeString}${this.getPunctuation(type)}`);
952 }
953 UnionTypeDefinition(node, key, parent) {
954 if (this.config.onlyOperationTypes)
955 return '';
956 const originalNode = parent[key];
957 const possibleTypes = originalNode.types
958 .map(t => (this.scalars[t.name.value] ? this._getScalar(t.name.value) : this.convertName(t)))
959 .join(' | ');
960 return new DeclarationBlock(this._declarationBlockConfig)
961 .export()
962 .asKind('type')
963 .withName(this.convertName(node))
964 .withComment(node.description)
965 .withContent(possibleTypes).string;
966 }
967 mergeInterfaces(interfaces, hasOtherFields) {
968 return interfaces.join(' & ') + (interfaces.length && hasOtherFields ? ' & ' : '');
969 }
970 appendInterfacesAndFieldsToBlock(block, interfaces, fields) {
971 block.withContent(this.mergeInterfaces(interfaces, fields.length > 0));
972 block.withBlock(this.mergeAllFields(fields, interfaces.length > 0));
973 }
974 getObjectTypeDeclarationBlock(node, originalNode) {
975 const optionalTypename = this.config.nonOptionalTypename ? '__typename' : '__typename?';
976 const { type } = this._parsedConfig.declarationKind;
977 const allFields = [
978 ...(this.config.addTypename
979 ? [
980 indent(`${this.config.immutableTypes ? 'readonly ' : ''}${optionalTypename}: '${node.name}'${this.getPunctuation(type)}`),
981 ]
982 : []),
983 ...node.fields,
984 ];
985 const interfacesNames = originalNode.interfaces ? originalNode.interfaces.map(i => this.convertName(i)) : [];
986 const declarationBlock = new DeclarationBlock(this._declarationBlockConfig)
987 .export()
988 .asKind(type)
989 .withName(this.convertName(node))
990 .withComment(node.description);
991 if (type === 'interface' || type === 'class') {
992 if (interfacesNames.length > 0) {
993 declarationBlock.withContent('extends ' + interfacesNames.join(', ') + (allFields.length > 0 ? ' ' : ' {}'));
994 }
995 declarationBlock.withBlock(this.mergeAllFields(allFields, false));
996 }
997 else {
998 this.appendInterfacesAndFieldsToBlock(declarationBlock, interfacesNames, allFields);
999 }
1000 return declarationBlock;
1001 }
1002 getFieldComment(node) {
1003 let commentText = node.description;
1004 const deprecationDirective = node.directives.find((v) => v.name === 'deprecated');
1005 if (deprecationDirective) {
1006 const deprecationReason = this.getDeprecationReason(deprecationDirective);
1007 commentText = `${commentText ? `${commentText}\n` : ''}@deprecated ${deprecationReason}`;
1008 }
1009 const comment = transformComment(commentText, 1);
1010 return comment;
1011 }
1012 mergeAllFields(allFields, hasInterfaces) {
1013 return allFields.join('\n');
1014 }
1015 ObjectTypeDefinition(node, key, parent) {
1016 if (this.config.onlyOperationTypes)
1017 return '';
1018 const originalNode = parent[key];
1019 return [this.getObjectTypeDeclarationBlock(node, originalNode).string, this.buildArgumentsBlock(originalNode)]
1020 .filter(f => f)
1021 .join('\n\n');
1022 }
1023 getInterfaceTypeDeclarationBlock(node, originalNode) {
1024 const declarationBlock = new DeclarationBlock(this._declarationBlockConfig)
1025 .export()
1026 .asKind(this._parsedConfig.declarationKind.interface)
1027 .withName(this.convertName(node))
1028 .withComment(node.description);
1029 return declarationBlock.withBlock(node.fields.join('\n'));
1030 }
1031 InterfaceTypeDefinition(node, key, parent) {
1032 if (this.config.onlyOperationTypes)
1033 return '';
1034 const originalNode = parent[key];
1035 return [this.getInterfaceTypeDeclarationBlock(node, originalNode).string, this.buildArgumentsBlock(originalNode)]
1036 .filter(f => f)
1037 .join('\n\n');
1038 }
1039 ScalarTypeDefinition(node) {
1040 // We empty this because we handle scalars in a different way, see constructor.
1041 return '';
1042 }
1043 _buildTypeImport(identifier, source, asDefault = false) {
1044 if (asDefault) {
1045 return `import ${identifier} from '${source}';`;
1046 }
1047 return `import { ${identifier} } from '${source}';`;
1048 }
1049 handleEnumValueMapper(typeIdentifier, importIdentifier, sourceIdentifier, sourceFile) {
1050 const importStatement = this._buildTypeImport(importIdentifier || sourceIdentifier, sourceFile);
1051 if (importIdentifier !== sourceIdentifier || sourceIdentifier !== typeIdentifier) {
1052 return [importStatement, `import ${typeIdentifier} = ${sourceIdentifier};`];
1053 }
1054 return [importStatement];
1055 }
1056 getEnumsImports() {
1057 return flatMap(Object.keys(this.config.enumValues), enumName => {
1058 const mappedValue = this.config.enumValues[enumName];
1059 if (mappedValue.sourceFile) {
1060 if (mappedValue.isDefault) {
1061 return [this._buildTypeImport(mappedValue.typeIdentifier, mappedValue.sourceFile, true)];
1062 }
1063 return this.handleEnumValueMapper(mappedValue.typeIdentifier, mappedValue.importIdentifier, mappedValue.sourceIdentifier, mappedValue.sourceFile);
1064 }
1065 return [];
1066 }).filter(a => a);
1067 }
1068 EnumTypeDefinition(node) {
1069 const enumName = node.name;
1070 // In case of mapped external enum string
1071 if (this.config.enumValues[enumName] && this.config.enumValues[enumName].sourceFile) {
1072 return null;
1073 }
1074 return new DeclarationBlock(this._declarationBlockConfig)
1075 .export()
1076 .asKind('enum')
1077 .withName(this.convertName(node, { useTypesPrefix: this.config.enumPrefix }))
1078 .withComment(node.description)
1079 .withBlock(this.buildEnumValuesBlock(enumName, node.values)).string;
1080 }
1081 // We are using it in order to transform "description" field
1082 StringValue(node) {
1083 return node.value;
1084 }
1085 buildEnumValuesBlock(typeName, values) {
1086 return values
1087 .map(enumOption => {
1088 const optionName = this.convertName(enumOption, { useTypesPrefix: false, transformUnderscore: true });
1089 const comment = transformComment(enumOption.description, 1);
1090 let enumValue = enumOption.name;
1091 if (this.config.enumValues[typeName] &&
1092 this.config.enumValues[typeName].mappedValues &&
1093 typeof this.config.enumValues[typeName].mappedValues[enumValue] !== 'undefined') {
1094 enumValue = this.config.enumValues[typeName].mappedValues[enumValue];
1095 }
1096 return (comment +
1097 indent(`${optionName}${this._declarationBlockConfig.enumNameValueSeparator} ${wrapWithSingleQuotes(enumValue)}`));
1098 })
1099 .join(',\n');
1100 }
1101 DirectiveDefinition(node) {
1102 return '';
1103 }
1104 getArgumentsObjectDeclarationBlock(node, name, field) {
1105 return new DeclarationBlock(this._declarationBlockConfig)
1106 .export()
1107 .asKind(this._parsedConfig.declarationKind.arguments)
1108 .withName(this.convertName(name))
1109 .withComment(node.description)
1110 .withBlock(this._argumentsTransformer.transform(field.arguments));
1111 }
1112 getArgumentsObjectTypeDefinition(node, name, field) {
1113 return this.getArgumentsObjectDeclarationBlock(node, name, field).string;
1114 }
1115 buildArgumentsBlock(node) {
1116 const fieldsWithArguments = node.fields.filter(field => field.arguments && field.arguments.length > 0) || [];
1117 return fieldsWithArguments
1118 .map(field => {
1119 const name = node.name.value +
1120 (this.config.addUnderscoreToArgsType ? '_' : '') +
1121 this.convertName(field, {
1122 useTypesPrefix: false,
1123 }) +
1124 'Args';
1125 return this.getArgumentsObjectTypeDefinition(node, name, field);
1126 })
1127 .join('\n\n');
1128 }
1129 _getScalar(name) {
1130 return `Scalars['${name}']`;
1131 }
1132 _getTypeForNode(node) {
1133 const typeAsString = node.name;
1134 if (this.scalars[typeAsString]) {
1135 return this._getScalar(typeAsString);
1136 }
1137 else if (this.config.enumValues[typeAsString]) {
1138 return this.config.enumValues[typeAsString].typeIdentifier;
1139 }
1140 const schemaType = this._schema.getType(node.name);
1141 if (schemaType && isEnumType(schemaType)) {
1142 return this.convertName(node, { useTypesPrefix: this.config.enumPrefix });
1143 }
1144 return this.convertName(node);
1145 }
1146 NamedType(node, key, parent, path, ancestors) {
1147 const currentVisitContext = this.getVisitorKindContextFromAncestors(ancestors);
1148 const isVisitingInputType = currentVisitContext.includes(Kind.INPUT_OBJECT_TYPE_DEFINITION);
1149 const typeToUse = this._getTypeForNode(node);
1150 if (!isVisitingInputType && this.config.fieldWrapperValue && this.config.wrapFieldDefinitions) {
1151 return `FieldWrapper<${typeToUse}>`;
1152 }
1153 return typeToUse;
1154 }
1155 ListType(node) {
1156 const asString = node.type;
1157 return this.wrapWithListType(asString);
1158 }
1159 SchemaDefinition() {
1160 return null;
1161 }
1162 getDeprecationReason(directive) {
1163 if (directive.name === 'deprecated') {
1164 const hasArguments = directive.arguments.length > 0;
1165 let reason = 'Field no longer supported';
1166 if (hasArguments) {
1167 reason = directive.arguments[0].value;
1168 }
1169 return reason;
1170 }
1171 }
1172 wrapWithListType(str) {
1173 return `Array<${str}>`;
1174 }
1175}
1176
1177function getRootType(operation, schema) {
1178 switch (operation) {
1179 case 'query':
1180 return schema.getQueryType();
1181 case 'mutation':
1182 return schema.getMutationType();
1183 case 'subscription':
1184 return schema.getSubscriptionType();
1185 }
1186}
1187class BaseDocumentsVisitor extends BaseVisitor {
1188 constructor(rawConfig, additionalConfig, _schema, defaultScalars = DEFAULT_SCALARS) {
1189 super(rawConfig, {
1190 exportFragmentSpreadSubTypes: getConfigValue(rawConfig.exportFragmentSpreadSubTypes, false),
1191 enumPrefix: getConfigValue(rawConfig.enumPrefix, true),
1192 preResolveTypes: getConfigValue(rawConfig.preResolveTypes, false),
1193 dedupeOperationSuffix: getConfigValue(rawConfig.dedupeOperationSuffix, false),
1194 omitOperationSuffix: getConfigValue(rawConfig.omitOperationSuffix, false),
1195 skipTypeNameForRoot: getConfigValue(rawConfig.skipTypeNameForRoot, false),
1196 namespacedImportName: getConfigValue(rawConfig.namespacedImportName, null),
1197 addTypename: !rawConfig.skipTypename,
1198 globalNamespace: !!rawConfig.globalNamespace,
1199 operationResultSuffix: getConfigValue(rawConfig.operationResultSuffix, ''),
1200 scalars: buildScalars(_schema, rawConfig.scalars, defaultScalars),
1201 ...(additionalConfig || {}),
1202 });
1203 this._schema = _schema;
1204 this._unnamedCounter = 1;
1205 this._globalDeclarations = new Set();
1206 autoBind(this);
1207 this._variablesTransfomer = new OperationVariablesToObject(this.scalars, this.convertName, this.config.namespacedImportName);
1208 }
1209 getGlobalDeclarations(noExport = false) {
1210 return Array.from(this._globalDeclarations).map(t => (noExport ? t : `export ${t}`));
1211 }
1212 setSelectionSetHandler(handler) {
1213 this._selectionSetToObject = handler;
1214 }
1215 setDeclarationBlockConfig(config) {
1216 this._declarationBlockConfig = config;
1217 }
1218 setVariablesTransformer(variablesTransfomer) {
1219 this._variablesTransfomer = variablesTransfomer;
1220 }
1221 get schema() {
1222 return this._schema;
1223 }
1224 get addTypename() {
1225 return this._parsedConfig.addTypename;
1226 }
1227 handleAnonymousOperation(node) {
1228 const name = node.name && node.name.value;
1229 if (name) {
1230 return this.convertName(node, {
1231 useTypesPrefix: false,
1232 });
1233 }
1234 return this.convertName(this._unnamedCounter++ + '', {
1235 prefix: 'Unnamed_',
1236 suffix: '_',
1237 useTypesPrefix: false,
1238 });
1239 }
1240 FragmentDefinition(node) {
1241 const fragmentRootType = this._schema.getType(node.typeCondition.name.value);
1242 const selectionSet = this._selectionSetToObject.createNext(fragmentRootType, node.selectionSet);
1243 const fragmentSuffix = this.getFragmentSuffix(node);
1244 return selectionSet.transformFragmentSelectionSetToTypes(node.name.value, fragmentSuffix, this._declarationBlockConfig);
1245 }
1246 applyVariablesWrapper(variablesBlock) {
1247 return variablesBlock;
1248 }
1249 OperationDefinition(node) {
1250 const name = this.handleAnonymousOperation(node);
1251 const operationRootType = getRootType(node.operation, this._schema);
1252 if (!operationRootType) {
1253 throw new Error(`Unable to find root schema type for operation type "${node.operation}"!`);
1254 }
1255 const selectionSet = this._selectionSetToObject.createNext(operationRootType, node.selectionSet);
1256 const visitedOperationVariables = this._variablesTransfomer.transform(node.variableDefinitions);
1257 const operationType = pascalCase(node.operation);
1258 const operationTypeSuffix = this.getOperationSuffix(name, operationType);
1259 const operationResult = new DeclarationBlock(this._declarationBlockConfig)
1260 .export()
1261 .asKind('type')
1262 .withName(this.convertName(name, {
1263 suffix: operationTypeSuffix + this._parsedConfig.operationResultSuffix,
1264 }))
1265 .withContent(selectionSet.transformSelectionSet()).string;
1266 const operationVariables = new DeclarationBlock({
1267 ...this._declarationBlockConfig,
1268 blockTransformer: t => this.applyVariablesWrapper(t),
1269 })
1270 .export()
1271 .asKind('type')
1272 .withName(this.convertName(name, {
1273 suffix: operationTypeSuffix + 'Variables',
1274 }))
1275 .withBlock(visitedOperationVariables).string;
1276 return [operationVariables, operationResult].filter(r => r).join('\n\n');
1277 }
1278}
1279
1280class BaseResolversVisitor extends BaseVisitor {
1281 constructor(rawConfig, additionalConfig, _schema, defaultScalars = DEFAULT_SCALARS) {
1282 super(rawConfig, {
1283 immutableTypes: getConfigValue(rawConfig.immutableTypes, false),
1284 optionalResolveType: getConfigValue(rawConfig.optionalResolveType, false),
1285 enumPrefix: getConfigValue(rawConfig.enumPrefix, true),
1286 federation: getConfigValue(rawConfig.federation, false),
1287 resolverTypeWrapperSignature: getConfigValue(rawConfig.resolverTypeWrapperSignature, 'Promise<T> | T'),
1288 enumValues: parseEnumValues(_schema, rawConfig.enumValues),
1289 addUnderscoreToArgsType: getConfigValue(rawConfig.addUnderscoreToArgsType, false),
1290 contextType: parseMapper(rawConfig.contextType || 'any', 'ContextType'),
1291 fieldContextTypes: getConfigValue(rawConfig.fieldContextTypes, []),
1292 resolverTypeSuffix: getConfigValue(rawConfig.resolverTypeSuffix, 'Resolvers'),
1293 allResolversTypeName: getConfigValue(rawConfig.allResolversTypeName, 'Resolvers'),
1294 rootValueType: parseMapper(rawConfig.rootValueType || '{}', 'RootValueType'),
1295 namespacedImportName: getConfigValue(rawConfig.namespacedImportName, ''),
1296 avoidOptionals: getConfigValue(rawConfig.avoidOptionals, false),
1297 defaultMapper: rawConfig.defaultMapper
1298 ? parseMapper(rawConfig.defaultMapper || 'any', 'DefaultMapperType')
1299 : null,
1300 mappers: transformMappers(rawConfig.mappers || {}, rawConfig.mapperTypeSuffix),
1301 scalars: buildScalars(_schema, rawConfig.scalars, defaultScalars),
1302 ...(additionalConfig || {}),
1303 });
1304 this._schema = _schema;
1305 this._declarationBlockConfig = {};
1306 this._collectedResolvers = {};
1307 this._collectedDirectiveResolvers = {};
1308 this._usedMappers = {};
1309 this._resolversTypes = {};
1310 this._resolversParentTypes = {};
1311 this._rootTypeNames = [];
1312 this._globalDeclarations = new Set();
1313 this._hasScalars = false;
1314 this._hasFederation = false;
1315 autoBind(this);
1316 this._federation = new ApolloFederation({ enabled: this.config.federation, schema: this.schema });
1317 this._rootTypeNames = getRootTypeNames(_schema);
1318 this._variablesTransfomer = new OperationVariablesToObject(this.scalars, this.convertName, this.config.namespacedImportName);
1319 this._resolversTypes = this.createResolversFields(type => this.applyResolverTypeWrapper(type), type => this.clearResolverTypeWrapper(type), name => this.getTypeToUse(name));
1320 this._resolversParentTypes = this.createResolversFields(type => type, type => type, name => this.getParentTypeToUse(name), namedType => !isEnumType(namedType));
1321 this._fieldContextTypeMap = this.createFieldContextTypeMap();
1322 }
1323 getResolverTypeWrapperSignature() {
1324 return `export type ResolverTypeWrapper<T> = ${this.config.resolverTypeWrapperSignature};`;
1325 }
1326 shouldMapType(type, checkedBefore = {}, duringCheck = []) {
1327 if (checkedBefore[type.name] !== undefined) {
1328 return checkedBefore[type.name];
1329 }
1330 if (type.name.startsWith('__') || this.config.scalars[type.name]) {
1331 return false;
1332 }
1333 if (this.config.mappers[type.name]) {
1334 return true;
1335 }
1336 if (isObjectType(type) || isInterfaceType(type)) {
1337 const fields = type.getFields();
1338 return Object.keys(fields)
1339 .filter(fieldName => {
1340 const field = fields[fieldName];
1341 const fieldType = getBaseType(field.type);
1342 return !duringCheck.includes(fieldType.name);
1343 })
1344 .some(fieldName => {
1345 const field = fields[fieldName];
1346 const fieldType = getBaseType(field.type);
1347 if (checkedBefore[fieldType.name] !== undefined) {
1348 return checkedBefore[fieldType.name];
1349 }
1350 if (this.config.mappers[type.name]) {
1351 return true;
1352 }
1353 duringCheck.push(type.name);
1354 const innerResult = this.shouldMapType(fieldType, checkedBefore, duringCheck);
1355 return innerResult;
1356 });
1357 }
1358 return false;
1359 }
1360 convertName(node, options, applyNamespacedImport = false) {
1361 const sourceType = super.convertName(node, options);
1362 return `${applyNamespacedImport && this.config.namespacedImportName ? this.config.namespacedImportName + '.' : ''}${sourceType}`;
1363 }
1364 // Kamil: this one is heeeeavvyyyy
1365 createResolversFields(applyWrapper, clearWrapper, getTypeToUse, shouldInclude) {
1366 const allSchemaTypes = this._schema.getTypeMap();
1367 const nestedMapping = {};
1368 const typeNames = this._federation.filterTypeNames(Object.keys(allSchemaTypes));
1369 typeNames.forEach(typeName => {
1370 const schemaType = allSchemaTypes[typeName];
1371 nestedMapping[typeName] = this.shouldMapType(schemaType, nestedMapping);
1372 });
1373 return typeNames.reduce((prev, typeName) => {
1374 const schemaType = allSchemaTypes[typeName];
1375 if (typeName.startsWith('__') || (shouldInclude && !shouldInclude(schemaType))) {
1376 return prev;
1377 }
1378 let shouldApplyOmit = false;
1379 const isRootType = this._rootTypeNames.includes(typeName);
1380 const isMapped = this.config.mappers[typeName];
1381 const isScalar = this.config.scalars[typeName];
1382 const hasDefaultMapper = !!(this.config.defaultMapper && this.config.defaultMapper.type);
1383 if (isRootType) {
1384 prev[typeName] = applyWrapper(this.config.rootValueType.type);
1385 return prev;
1386 }
1387 else if (isInterfaceType(schemaType)) {
1388 const allTypesMap = this._schema.getTypeMap();
1389 const implementingTypes = [];
1390 for (const graphqlType of Object.values(allTypesMap)) {
1391 if (graphqlType instanceof GraphQLObjectType) {
1392 const allInterfaces = graphqlType.getInterfaces();
1393 if (allInterfaces.some(int => int.name === schemaType.name)) {
1394 implementingTypes.push(graphqlType.name);
1395 }
1396 }
1397 }
1398 const possibleTypes = implementingTypes.map(name => getTypeToUse(name)).join(' | ') || 'never';
1399 prev[typeName] = possibleTypes;
1400 return prev;
1401 }
1402 else if (isEnumType(schemaType) && this.config.enumValues[typeName]) {
1403 prev[typeName] =
1404 this.config.enumValues[typeName].sourceIdentifier ||
1405 this.convertName(this.config.enumValues[typeName].typeIdentifier);
1406 }
1407 else if (isMapped && this.config.mappers[typeName].type) {
1408 this.markMapperAsUsed(typeName);
1409 prev[typeName] = applyWrapper(this.config.mappers[typeName].type);
1410 }
1411 else if (hasDefaultMapper && !hasPlaceholder(this.config.defaultMapper.type)) {
1412 prev[typeName] = applyWrapper(this.config.defaultMapper.type);
1413 }
1414 else if (isScalar) {
1415 prev[typeName] = applyWrapper(this._getScalar(typeName));
1416 }
1417 else if (isUnionType(schemaType)) {
1418 prev[typeName] = schemaType
1419 .getTypes()
1420 .map(type => getTypeToUse(type.name))
1421 .join(' | ');
1422 }
1423 else {
1424 shouldApplyOmit = true;
1425 prev[typeName] = this.convertName(typeName, { useTypesPrefix: this.config.enumPrefix }, true);
1426 }
1427 if (shouldApplyOmit && prev[typeName] !== 'any' && isObjectType(schemaType)) {
1428 const fields = schemaType.getFields();
1429 const relevantFields = this._federation
1430 .filterFieldNames(Object.keys(fields))
1431 .map(fieldName => {
1432 const field = fields[fieldName];
1433 const baseType = getBaseType(field.type);
1434 const isUnion = isUnionType(baseType);
1435 if (!this.config.mappers[baseType.name] && !isUnion && !nestedMapping[baseType.name]) {
1436 return null;
1437 }
1438 const addOptionalSign = !this.config.avoidOptionals && !isNonNullType(field.type);
1439 return {
1440 addOptionalSign,
1441 fieldName,
1442 replaceWithType: wrapTypeWithModifiers(getTypeToUse(baseType.name), field.type, {
1443 wrapOptional: this.applyMaybe,
1444 wrapArray: this.wrapWithArray,
1445 }),
1446 };
1447 })
1448 .filter(a => a);
1449 if (relevantFields.length > 0) {
1450 // Puts ResolverTypeWrapper on top of an entire type
1451 prev[typeName] = applyWrapper(this.replaceFieldsInType(prev[typeName], relevantFields));
1452 }
1453 else {
1454 // We still want to use ResolverTypeWrapper, even if we don't touch any fields
1455 prev[typeName] = applyWrapper(prev[typeName]);
1456 }
1457 }
1458 if (isMapped && hasPlaceholder(prev[typeName])) {
1459 prev[typeName] = replacePlaceholder(prev[typeName], typeName);
1460 }
1461 if (!isMapped && hasDefaultMapper && hasPlaceholder(this.config.defaultMapper.type)) {
1462 // Make sure the inner type has no ResolverTypeWrapper
1463 const name = clearWrapper(isScalar ? this._getScalar(typeName) : prev[typeName]);
1464 const replaced = replacePlaceholder(this.config.defaultMapper.type, name);
1465 // Don't wrap Union with ResolverTypeWrapper, each inner type already has it
1466 if (isUnionType(schemaType)) {
1467 prev[typeName] = replaced;
1468 }
1469 else {
1470 prev[typeName] = applyWrapper(replacePlaceholder(this.config.defaultMapper.type, name));
1471 }
1472 }
1473 return prev;
1474 }, {});
1475 }
1476 replaceFieldsInType(typeName, relevantFields) {
1477 this._globalDeclarations.add(OMIT_TYPE);
1478 return `Omit<${typeName}, ${relevantFields.map(f => `'${f.fieldName}'`).join(' | ')}> & { ${relevantFields
1479 .map(f => `${f.fieldName}${f.addOptionalSign ? '?' : ''}: ${f.replaceWithType}`)
1480 .join(', ')} }`;
1481 }
1482 applyMaybe(str) {
1483 return `Maybe<${str}>`;
1484 }
1485 applyResolverTypeWrapper(str) {
1486 return `ResolverTypeWrapper<${this.clearResolverTypeWrapper(str)}>`;
1487 }
1488 clearMaybe(str) {
1489 if (str.startsWith('Maybe<')) {
1490 return str.replace(/Maybe<(.*?)>$/, '$1');
1491 }
1492 return str;
1493 }
1494 clearResolverTypeWrapper(str) {
1495 if (str.startsWith('ResolverTypeWrapper<')) {
1496 return str.replace(/ResolverTypeWrapper<(.*?)>$/, '$1');
1497 }
1498 return str;
1499 }
1500 wrapWithArray(t) {
1501 if (this.config.immutableTypes) {
1502 return `ReadonlyArray<${t}>`;
1503 }
1504 return `Array<${t}>`;
1505 }
1506 createFieldContextTypeMap() {
1507 return this.config.fieldContextTypes.reduce((prev, fieldContextType) => {
1508 const items = fieldContextType.split('#');
1509 if (items.length === 3) {
1510 const [path, source, contextTypeName] = items;
1511 return { ...prev, [path]: parseMapper(`${source}#${contextTypeName}`) };
1512 }
1513 const [path, contextType] = items;
1514 return { ...prev, [path]: parseMapper(contextType) };
1515 }, {});
1516 }
1517 buildResolversTypes() {
1518 const declarationKind = 'type';
1519 return new DeclarationBlock(this._declarationBlockConfig)
1520 .export()
1521 .asKind(declarationKind)
1522 .withName(this.convertName('ResolversTypes'))
1523 .withComment('Mapping between all available schema types and the resolvers types')
1524 .withBlock(Object.keys(this._resolversTypes)
1525 .map(typeName => indent(`${typeName}: ${this._resolversTypes[typeName]}${this.getPunctuation(declarationKind)}`))
1526 .join('\n')).string;
1527 }
1528 buildResolversParentTypes() {
1529 const declarationKind = 'type';
1530 return new DeclarationBlock(this._declarationBlockConfig)
1531 .export()
1532 .asKind(declarationKind)
1533 .withName(this.convertName('ResolversParentTypes'))
1534 .withComment('Mapping between all available schema types and the resolvers parents')
1535 .withBlock(Object.keys(this._resolversParentTypes)
1536 .map(typeName => indent(`${typeName}: ${this._resolversParentTypes[typeName]}${this.getPunctuation(declarationKind)}`))
1537 .join('\n')).string;
1538 }
1539 get schema() {
1540 return this._schema;
1541 }
1542 get defaultMapperType() {
1543 return this.config.defaultMapper.type;
1544 }
1545 get unusedMappers() {
1546 return Object.keys(this.config.mappers).filter(name => !this._usedMappers[name]);
1547 }
1548 get globalDeclarations() {
1549 return Array.from(this._globalDeclarations);
1550 }
1551 isMapperImported(groupedMappers, identifier, source) {
1552 const exists = !groupedMappers[source] ? false : !!groupedMappers[source].find(m => m.identifier === identifier);
1553 const existsFromEnums = !!Object.keys(this.config.enumValues)
1554 .map(key => this.config.enumValues[key])
1555 .find(o => o.sourceFile === source && o.typeIdentifier === identifier);
1556 return exists || existsFromEnums;
1557 }
1558 get mappersImports() {
1559 const groupedMappers = {};
1560 const addMapper = (source, identifier, asDefault) => {
1561 if (!this.isMapperImported(groupedMappers, identifier, source)) {
1562 if (!groupedMappers[source]) {
1563 groupedMappers[source] = [];
1564 }
1565 groupedMappers[source].push({ identifier, asDefault });
1566 }
1567 };
1568 Object.keys(this.config.mappers)
1569 .map(gqlTypeName => ({ gqlType: gqlTypeName, mapper: this.config.mappers[gqlTypeName] }))
1570 .filter(({ mapper }) => mapper.isExternal)
1571 .forEach(({ mapper }) => {
1572 const externalMapper = mapper;
1573 const identifier = stripMapperTypeInterpolation(externalMapper.import);
1574 addMapper(externalMapper.source, identifier, externalMapper.default);
1575 });
1576 if (this.config.contextType.isExternal) {
1577 addMapper(this.config.contextType.source, this.config.contextType.import, this.config.contextType.default);
1578 }
1579 if (this.config.rootValueType.isExternal) {
1580 addMapper(this.config.rootValueType.source, this.config.rootValueType.import, this.config.rootValueType.default);
1581 }
1582 if (this.config.defaultMapper && this.config.defaultMapper.isExternal) {
1583 const identifier = stripMapperTypeInterpolation(this.config.defaultMapper.import);
1584 addMapper(this.config.defaultMapper.source, identifier, this.config.defaultMapper.default);
1585 }
1586 Object.values(this._fieldContextTypeMap).forEach(parsedMapper => {
1587 if (parsedMapper.isExternal) {
1588 addMapper(parsedMapper.source, parsedMapper.import, parsedMapper.default);
1589 }
1590 });
1591 return Object.keys(groupedMappers)
1592 .map(source => this.buildMapperImport(source, groupedMappers[source]))
1593 .filter(Boolean);
1594 }
1595 buildMapperImport(source, types) {
1596 if (!types || types.length === 0) {
1597 return null;
1598 }
1599 const defaultType = types.find(t => t.asDefault === true);
1600 const namedTypes = types.filter(t => !t.asDefault);
1601 // { Foo, Bar as BarModel }
1602 const namedImports = namedTypes.length ? `{ ${namedTypes.map(t => t.identifier).join(', ')} }` : '';
1603 // Baz
1604 const defaultImport = defaultType ? defaultType.identifier : '';
1605 // Baz, { Foo, Bar as BarModel }
1606 return `import ${[defaultImport, namedImports].filter(Boolean).join(', ')} from '${source}';`;
1607 }
1608 setDeclarationBlockConfig(config) {
1609 this._declarationBlockConfig = config;
1610 }
1611 setVariablesTransformer(variablesTransfomer) {
1612 this._variablesTransfomer = variablesTransfomer;
1613 }
1614 hasScalars() {
1615 return this._hasScalars;
1616 }
1617 hasFederation() {
1618 return this._hasFederation;
1619 }
1620 getRootResolver() {
1621 const name = this.convertName(this.config.allResolversTypeName);
1622 const declarationKind = 'type';
1623 const contextType = `<ContextType = ${this.config.contextType.type}>`;
1624 // This is here because we don't want to break IResolvers, so there is a mapping by default,
1625 // and if the developer is overriding typesPrefix, it won't get generated at all.
1626 const deprecatedIResolvers = !this.config.typesPrefix
1627 ? `
1628/**
1629 * @deprecated
1630 * Use "Resolvers" root object instead. If you wish to get "IResolvers", add "typesPrefix: I" to your config.
1631 */
1632export type IResolvers${contextType} = ${name}<ContextType>;`
1633 : '';
1634 return [
1635 new DeclarationBlock(this._declarationBlockConfig)
1636 .export()
1637 .asKind(declarationKind)
1638 .withName(name, contextType)
1639 .withBlock(Object.keys(this._collectedResolvers)
1640 .map(schemaTypeName => {
1641 const resolverType = this._collectedResolvers[schemaTypeName];
1642 return indent(this.formatRootResolver(schemaTypeName, resolverType, declarationKind));
1643 })
1644 .join('\n')).string,
1645 deprecatedIResolvers,
1646 ].join('\n');
1647 }
1648 formatRootResolver(schemaTypeName, resolverType, declarationKind) {
1649 return `${schemaTypeName}${this.config.avoidOptionals ? '' : '?'}: ${resolverType}${this.getPunctuation(declarationKind)}`;
1650 }
1651 getAllDirectiveResolvers() {
1652 if (Object.keys(this._collectedDirectiveResolvers).length) {
1653 const declarationKind = 'type';
1654 const name = this.convertName('DirectiveResolvers');
1655 const contextType = `<ContextType = ${this.config.contextType.type}>`;
1656 // This is here because we don't want to break IResolvers, so there is a mapping by default,
1657 // and if the developer is overriding typesPrefix, it won't get generated at all.
1658 const deprecatedIResolvers = !this.config.typesPrefix
1659 ? `
1660/**
1661 * @deprecated
1662 * Use "DirectiveResolvers" root object instead. If you wish to get "IDirectiveResolvers", add "typesPrefix: I" to your config.
1663 */
1664export type IDirectiveResolvers${contextType} = ${name}<ContextType>;`
1665 : '';
1666 return [
1667 new DeclarationBlock(this._declarationBlockConfig)
1668 .export()
1669 .asKind(declarationKind)
1670 .withName(name, contextType)
1671 .withBlock(Object.keys(this._collectedDirectiveResolvers)
1672 .map(schemaTypeName => {
1673 const resolverType = this._collectedDirectiveResolvers[schemaTypeName];
1674 return indent(this.formatRootResolver(schemaTypeName, resolverType, declarationKind));
1675 })
1676 .join('\n')).string,
1677 deprecatedIResolvers,
1678 ].join('\n');
1679 }
1680 return '';
1681 }
1682 Name(node) {
1683 return node.value;
1684 }
1685 ListType(node) {
1686 const asString = node.type;
1687 return this.wrapWithArray(asString);
1688 }
1689 _getScalar(name) {
1690 return `${this.config.namespacedImportName ? this.config.namespacedImportName + '.' : ''}Scalars['${name}']`;
1691 }
1692 NamedType(node) {
1693 const nameStr = node.name;
1694 if (this.config.scalars[nameStr]) {
1695 return this._getScalar(nameStr);
1696 }
1697 return this.convertName(node, null, true);
1698 }
1699 NonNullType(node) {
1700 const asString = node.type;
1701 return asString;
1702 }
1703 markMapperAsUsed(name) {
1704 this._usedMappers[name] = true;
1705 }
1706 getTypeToUse(name) {
1707 const resolversType = this.convertName('ResolversTypes');
1708 return `${resolversType}['${name}']`;
1709 }
1710 getParentTypeToUse(name) {
1711 const resolversType = this.convertName('ResolversParentTypes');
1712 return `${resolversType}['${name}']`;
1713 }
1714 getParentTypeForSignature(node) {
1715 return 'ParentType';
1716 }
1717 transformParentGenericType(parentType) {
1718 return `ParentType extends ${parentType} = ${parentType}`;
1719 }
1720 FieldDefinition(node, key, parent) {
1721 const hasArguments = node.arguments && node.arguments.length > 0;
1722 const declarationKind = 'type';
1723 return (parentName) => {
1724 const original = parent[key];
1725 const baseType = getBaseTypeNode(original.type);
1726 const realType = baseType.name.value;
1727 const parentType = this.schema.getType(parentName);
1728 if (this._federation.skipField({ fieldNode: original, parentType: parentType })) {
1729 return null;
1730 }
1731 const typeToUse = this.getTypeToUse(realType);
1732 const mappedType = this._variablesTransfomer.wrapAstTypeWithModifiers(typeToUse, original.type);
1733 const subscriptionType = this._schema.getSubscriptionType();
1734 const isSubscriptionType = subscriptionType && subscriptionType.name === parentName;
1735 let argsType = hasArguments
1736 ? `${this.convertName(parentName, {
1737 useTypesPrefix: true,
1738 }, true) +
1739 (this.config.addUnderscoreToArgsType ? '_' : '') +
1740 this.convertName(node.name, {
1741 useTypesPrefix: false,
1742 }) +
1743 'Args'}`
1744 : null;
1745 if (argsType !== null) {
1746 const argsToForceRequire = original.arguments.filter(arg => !!arg.defaultValue || arg.type.kind === 'NonNullType');
1747 if (argsToForceRequire.length > 0) {
1748 argsType = this.applyRequireFields(argsType, argsToForceRequire);
1749 }
1750 else if (original.arguments.length > 0) {
1751 argsType = this.applyOptionalFields(argsType, original.arguments);
1752 }
1753 }
1754 const parentTypeSignature = this._federation.transformParentType({
1755 fieldNode: original,
1756 parentType,
1757 parentTypeSignature: this.getParentTypeForSignature(node),
1758 });
1759 const mappedTypeKey = isSubscriptionType ? `${mappedType}, "${node.name}"` : mappedType;
1760 const signature = {
1761 name: node.name,
1762 modifier: this.config.avoidOptionals ? '' : '?',
1763 type: isSubscriptionType ? 'SubscriptionResolver' : 'Resolver',
1764 genericTypes: [
1765 mappedTypeKey,
1766 parentTypeSignature,
1767 this._fieldContextTypeMap[`${parentName}.${node.name}`]
1768 ? this._fieldContextTypeMap[`${parentName}.${node.name}`].type
1769 : 'ContextType',
1770 argsType,
1771 ].filter(f => f),
1772 };
1773 if (this._federation.isResolveReferenceField(node)) {
1774 this._hasFederation = true;
1775 signature.type = 'ReferenceResolver';
1776 if (signature.genericTypes.length >= 3) {
1777 signature.genericTypes = signature.genericTypes.slice(0, 3);
1778 }
1779 }
1780 return indent(`${signature.name}${signature.modifier}: ${signature.type}<${signature.genericTypes.join(', ')}>${this.getPunctuation(declarationKind)}`);
1781 };
1782 }
1783 applyRequireFields(argsType, fields) {
1784 this._globalDeclarations.add(REQUIRE_FIELDS_TYPE);
1785 return `RequireFields<${argsType}, ${fields.map(f => `'${f.name.value}'`).join(' | ')}>`;
1786 }
1787 applyOptionalFields(argsType, fields) {
1788 this._globalDeclarations.add(REQUIRE_FIELDS_TYPE);
1789 return `RequireFields<${argsType}, never>`;
1790 }
1791 ObjectTypeDefinition(node) {
1792 var _a, _b, _c;
1793 const declarationKind = 'type';
1794 const name = this.convertName(node, {
1795 suffix: this.config.resolverTypeSuffix,
1796 });
1797 const typeName = node.name;
1798 const parentType = this.getParentTypeToUse(typeName);
1799 const isRootType = [
1800 (_a = this.schema.getQueryType()) === null || _a === void 0 ? void 0 : _a.name,
1801 (_b = this.schema.getMutationType()) === null || _b === void 0 ? void 0 : _b.name,
1802 (_c = this.schema.getSubscriptionType()) === null || _c === void 0 ? void 0 : _c.name,
1803 ].includes(typeName);
1804 const fieldsContent = node.fields.map((f) => f(node.name));
1805 if (!isRootType) {
1806 fieldsContent.push(indent(`__isTypeOf?: IsTypeOfResolverFn<ParentType>${this.getPunctuation(declarationKind)}`));
1807 }
1808 const block = new DeclarationBlock(this._declarationBlockConfig)
1809 .export()
1810 .asKind(declarationKind)
1811 .withName(name, `<ContextType = ${this.config.contextType.type}, ${this.transformParentGenericType(parentType)}>`)
1812 .withBlock(fieldsContent.join('\n'));
1813 this._collectedResolvers[node.name] = name + '<ContextType>';
1814 return block.string;
1815 }
1816 UnionTypeDefinition(node, key, parent) {
1817 const declarationKind = 'type';
1818 const name = this.convertName(node, {
1819 suffix: this.config.resolverTypeSuffix,
1820 });
1821 const originalNode = parent[key];
1822 const possibleTypes = originalNode.types
1823 .map(node => node.name.value)
1824 .map(f => `'${f}'`)
1825 .join(' | ');
1826 this._collectedResolvers[node.name] = name + '<ContextType>';
1827 const parentType = this.getParentTypeToUse(node.name);
1828 return new DeclarationBlock(this._declarationBlockConfig)
1829 .export()
1830 .asKind(declarationKind)
1831 .withName(name, `<ContextType = ${this.config.contextType.type}, ${this.transformParentGenericType(parentType)}>`)
1832 .withBlock(indent(`__resolveType${this.config.optionalResolveType ? '?' : ''}: TypeResolveFn<${possibleTypes}, ParentType, ContextType>${this.getPunctuation(declarationKind)}`)).string;
1833 }
1834 ScalarTypeDefinition(node) {
1835 const nameAsString = node.name;
1836 const baseName = this.getTypeToUse(nameAsString);
1837 if (this._federation.skipScalar(nameAsString)) {
1838 return null;
1839 }
1840 this._hasScalars = true;
1841 this._collectedResolvers[node.name] = 'GraphQLScalarType';
1842 return new DeclarationBlock({
1843 ...this._declarationBlockConfig,
1844 blockTransformer(block) {
1845 return block;
1846 },
1847 })
1848 .export()
1849 .asKind('interface')
1850 .withName(this.convertName(node, {
1851 suffix: 'ScalarConfig',
1852 }), ` extends GraphQLScalarTypeConfig<${baseName}, any>`)
1853 .withBlock(indent(`name: '${node.name}'${this.getPunctuation('interface')}`)).string;
1854 }
1855 DirectiveDefinition(node, key, parent) {
1856 if (this._federation.skipDirective(node.name)) {
1857 return null;
1858 }
1859 const directiveName = this.convertName(node, {
1860 suffix: 'DirectiveResolver',
1861 });
1862 const sourceNode = parent[key];
1863 const hasArguments = sourceNode.arguments && sourceNode.arguments.length > 0;
1864 this._collectedDirectiveResolvers[node.name] = directiveName + '<any, any, ContextType>';
1865 const directiveArgsTypeName = this.convertName(node, {
1866 suffix: 'DirectiveArgs',
1867 });
1868 return [
1869 new DeclarationBlock({
1870 ...this._declarationBlockConfig,
1871 blockTransformer(block) {
1872 return block;
1873 },
1874 })
1875 .export()
1876 .asKind('type')
1877 .withName(directiveArgsTypeName)
1878 .withContent(`{ ${hasArguments ? this._variablesTransfomer.transform(sourceNode.arguments) : ''} }`).string,
1879 new DeclarationBlock({
1880 ...this._declarationBlockConfig,
1881 blockTransformer(block) {
1882 return block;
1883 },
1884 })
1885 .export()
1886 .asKind('type')
1887 .withName(directiveName, `<Result, Parent, ContextType = ${this.config.contextType.type}, Args = ${directiveArgsTypeName}>`)
1888 .withContent(`DirectiveResolverFn<Result, Parent, ContextType, Args>`).string,
1889 ].join('\n');
1890 }
1891 buildEnumResolverContentBlock(node, mappedEnumType) {
1892 throw new Error(`buildEnumResolverContentBlock is not implemented!`);
1893 }
1894 buildEnumResolversExplicitMappedValues(node, valuesMapping) {
1895 throw new Error(`buildEnumResolversExplicitMappedValues is not implemented!`);
1896 }
1897 EnumTypeDefinition(node) {
1898 const rawTypeName = node.name;
1899 // If we have enumValues set, and it's point to an external enum - we need to allow internal values resolvers
1900 // In case we have enumValues set but as explicit values, no need to to do mapping since it's already
1901 // have type validation (the original enum has been modified by base types plugin).
1902 // If we have mapper for that type - we can skip
1903 if (!this.config.mappers[rawTypeName] && !this.config.enumValues[rawTypeName]) {
1904 return null;
1905 }
1906 const name = this.convertName(node, { suffix: this.config.resolverTypeSuffix });
1907 this._collectedResolvers[rawTypeName] = name;
1908 const hasExplicitValues = this.config.enumValues[rawTypeName] && this.config.enumValues[rawTypeName].mappedValues;
1909 return new DeclarationBlock(this._declarationBlockConfig)
1910 .export()
1911 .asKind('type')
1912 .withName(name)
1913 .withContent(hasExplicitValues
1914 ? this.buildEnumResolversExplicitMappedValues(node, this.config.enumValues[rawTypeName].mappedValues)
1915 : this.buildEnumResolverContentBlock(node, this.getTypeToUse(rawTypeName))).string;
1916 }
1917 InterfaceTypeDefinition(node) {
1918 const name = this.convertName(node, {
1919 suffix: this.config.resolverTypeSuffix,
1920 });
1921 const declarationKind = 'type';
1922 const allTypesMap = this._schema.getTypeMap();
1923 const implementingTypes = [];
1924 this._collectedResolvers[node.name] = name + '<ContextType>';
1925 for (const graphqlType of Object.values(allTypesMap)) {
1926 if (graphqlType instanceof GraphQLObjectType) {
1927 const allInterfaces = graphqlType.getInterfaces();
1928 if (allInterfaces.find(int => int.name === node.name)) {
1929 implementingTypes.push(graphqlType.name);
1930 }
1931 }
1932 }
1933 const parentType = this.getParentTypeToUse(node.name);
1934 const possibleTypes = implementingTypes.map(name => `'${name}'`).join(' | ') || 'null';
1935 return new DeclarationBlock(this._declarationBlockConfig)
1936 .export()
1937 .asKind(declarationKind)
1938 .withName(name, `<ContextType = ${this.config.contextType.type}, ${this.transformParentGenericType(parentType)}>`)
1939 .withBlock([
1940 indent(`__resolveType${this.config.optionalResolveType ? '?' : ''}: TypeResolveFn<${possibleTypes}, ParentType, ContextType>${this.getPunctuation(declarationKind)}`),
1941 ...(node.fields || []).map((f) => f(node.name)),
1942 ].join('\n')).string;
1943 }
1944 SchemaDefinition() {
1945 return null;
1946 }
1947}
1948function replacePlaceholder(pattern, typename) {
1949 return pattern.replace('{T}', typename);
1950}
1951function hasPlaceholder(pattern) {
1952 return pattern.includes('{T}');
1953}
1954
1955var DocumentMode;
1956(function (DocumentMode) {
1957 DocumentMode["graphQLTag"] = "graphQLTag";
1958 DocumentMode["documentNode"] = "documentNode";
1959 DocumentMode["documentNodeImportFragments"] = "documentNodeImportFragments";
1960 DocumentMode["external"] = "external";
1961 DocumentMode["string"] = "string";
1962})(DocumentMode || (DocumentMode = {}));
1963const EXTENSIONS_TO_REMOVE = ['.ts', '.tsx', '.js', '.jsx'];
1964class ClientSideBaseVisitor extends BaseVisitor {
1965 constructor(_schema, _fragments, rawConfig, additionalConfig, documents) {
1966 super(rawConfig, {
1967 scalars: buildScalars(_schema, rawConfig.scalars, DEFAULT_SCALARS),
1968 dedupeOperationSuffix: getConfigValue(rawConfig.dedupeOperationSuffix, false),
1969 omitOperationSuffix: getConfigValue(rawConfig.omitOperationSuffix, false),
1970 gqlImport: rawConfig.gqlImport || null,
1971 noExport: !!rawConfig.noExport,
1972 importOperationTypesFrom: getConfigValue(rawConfig.importOperationTypesFrom, null),
1973 operationResultSuffix: getConfigValue(rawConfig.operationResultSuffix, ''),
1974 documentVariablePrefix: getConfigValue(rawConfig.documentVariablePrefix, ''),
1975 documentVariableSuffix: getConfigValue(rawConfig.documentVariableSuffix, 'Document'),
1976 fragmentVariablePrefix: getConfigValue(rawConfig.fragmentVariablePrefix, ''),
1977 fragmentVariableSuffix: getConfigValue(rawConfig.fragmentVariableSuffix, 'FragmentDoc'),
1978 documentMode: ((rawConfig) => {
1979 if (typeof rawConfig.noGraphQLTag === 'boolean') {
1980 return rawConfig.noGraphQLTag ? DocumentMode.documentNode : DocumentMode.graphQLTag;
1981 }
1982 return getConfigValue(rawConfig.documentMode, DocumentMode.graphQLTag);
1983 })(rawConfig),
1984 importDocumentNodeExternallyFrom: getConfigValue(rawConfig.importDocumentNodeExternallyFrom, ''),
1985 pureMagicComment: getConfigValue(rawConfig.pureMagicComment, false),
1986 ...additionalConfig,
1987 });
1988 this._schema = _schema;
1989 this._fragments = _fragments;
1990 this._collectedOperations = [];
1991 this._documents = [];
1992 this._additionalImports = [];
1993 this._documents = documents;
1994 autoBind(this);
1995 }
1996 _extractFragments(document, withNested = false) {
1997 if (!document) {
1998 return [];
1999 }
2000 const names = new Set();
2001 visit(document, {
2002 enter: {
2003 FragmentSpread: (node) => {
2004 names.add(node.name.value);
2005 if (withNested) {
2006 const foundFragment = this._fragments.find(f => f.name === node.name.value);
2007 if (foundFragment) {
2008 const childItems = this._extractFragments(foundFragment.node, true);
2009 if (childItems && childItems.length > 0) {
2010 for (const item of childItems) {
2011 names.add(item);
2012 }
2013 }
2014 }
2015 }
2016 },
2017 },
2018 });
2019 return Array.from(names);
2020 }
2021 _transformFragments(document) {
2022 const includeNestedFragments = this.config.documentMode === DocumentMode.documentNode;
2023 return this._extractFragments(document, includeNestedFragments).map(document => this.getFragmentVariableName(document));
2024 }
2025 _includeFragments(fragments) {
2026 if (fragments && fragments.length > 0) {
2027 if (this.config.documentMode === DocumentMode.documentNode) {
2028 return this._fragments
2029 .filter(f => fragments.includes(this.getFragmentVariableName(f.name)))
2030 .map(fragment => print(fragment.node))
2031 .join('\n');
2032 }
2033 else if (this.config.documentMode === DocumentMode.documentNodeImportFragments) {
2034 return '';
2035 }
2036 else {
2037 return `${fragments.map(name => '${' + name + '}').join('\n')}`;
2038 }
2039 }
2040 return '';
2041 }
2042 _prepareDocument(documentStr) {
2043 return documentStr;
2044 }
2045 _gql(node) {
2046 const fragments = this._transformFragments(node);
2047 const doc = this._prepareDocument(`
2048 ${print(node)
2049 .split('\\')
2050 .join('\\\\') /* Re-escape escaped values in GraphQL syntax */}
2051 ${this._includeFragments(fragments)}`);
2052 if (this.config.documentMode === DocumentMode.documentNode) {
2053 const gqlObj = gqlTag([doc]);
2054 if (gqlObj && gqlObj.loc) {
2055 delete gqlObj.loc;
2056 }
2057 return JSON.stringify(gqlObj);
2058 }
2059 else if (this.config.documentMode === DocumentMode.documentNodeImportFragments) {
2060 const gqlObj = gqlTag([doc]);
2061 if (gqlObj && gqlObj.loc) {
2062 delete gqlObj.loc;
2063 }
2064 if (fragments.length > 0) {
2065 const definitions = [
2066 ...gqlObj.definitions.map(t => JSON.stringify(t)),
2067 ...fragments.map(name => `...${name}.definitions`),
2068 ].join();
2069 return `{"kind":"${Kind.DOCUMENT}","definitions":[${definitions}]}`;
2070 }
2071 return JSON.stringify(gqlObj);
2072 }
2073 else if (this.config.documentMode === DocumentMode.string) {
2074 return '`' + doc + '`';
2075 }
2076 return 'gql`' + doc + '`';
2077 }
2078 _generateFragment(fragmentDocument) {
2079 const name = this.getFragmentVariableName(fragmentDocument);
2080 const isDocumentNode = this.config.documentMode === DocumentMode.documentNode ||
2081 this.config.documentMode === DocumentMode.documentNodeImportFragments;
2082 return `export const ${name}${isDocumentNode ? ': DocumentNode' : ''} =${this.config.pureMagicComment ? ' /*#__PURE__*/' : ''} ${this._gql(fragmentDocument)};`;
2083 }
2084 get fragmentsGraph() {
2085 const graph = new DepGraph({ circular: true });
2086 for (const fragment of this._fragments) {
2087 if (graph.hasNode(fragment.name)) {
2088 const cachedAsString = print(graph.getNodeData(fragment.name).node);
2089 const asString = print(fragment.node);
2090 if (cachedAsString !== asString) {
2091 throw new Error(`Duplicated fragment called '${fragment.name}'!`);
2092 }
2093 }
2094 graph.addNode(fragment.name, fragment);
2095 }
2096 this._fragments.forEach(fragment => {
2097 const depends = this._extractFragments(fragment.node);
2098 if (depends && depends.length > 0) {
2099 depends.forEach(name => {
2100 graph.addDependency(fragment.name, name);
2101 });
2102 }
2103 });
2104 return graph;
2105 }
2106 get fragments() {
2107 if (this._fragments.length === 0 || this.config.documentMode === DocumentMode.external) {
2108 return '';
2109 }
2110 const graph = this.fragmentsGraph;
2111 const orderedDeps = graph.overallOrder();
2112 const localFragments = orderedDeps
2113 .filter(name => !graph.getNodeData(name).isExternal)
2114 .map(name => this._generateFragment(graph.getNodeData(name).node));
2115 return localFragments.join('\n');
2116 }
2117 _parseImport(importStr) {
2118 const [moduleName, propName] = importStr.split('#');
2119 return {
2120 moduleName,
2121 propName,
2122 };
2123 }
2124 clearExtension(path) {
2125 const extension = extname(path);
2126 if (EXTENSIONS_TO_REMOVE.includes(extension)) {
2127 return path.replace(/\.[^/.]+$/, '');
2128 }
2129 return path;
2130 }
2131 getImports(options = {}) {
2132 const imports = [...this._additionalImports];
2133 switch (this.config.documentMode) {
2134 case DocumentMode.documentNode:
2135 case DocumentMode.documentNodeImportFragments: {
2136 imports.push(`import { DocumentNode } from 'graphql';`);
2137 break;
2138 }
2139 case DocumentMode.graphQLTag: {
2140 const gqlImport = this._parseImport(this.config.gqlImport || 'graphql-tag');
2141 imports.push(`import ${gqlImport.propName ? `{ ${gqlImport.propName === 'gql' ? 'gql' : `${gqlImport.propName} as gql`} }` : 'gql'} from '${gqlImport.moduleName}';`);
2142 break;
2143 }
2144 case DocumentMode.external: {
2145 if (this._collectedOperations.length > 0) {
2146 if (this.config.importDocumentNodeExternallyFrom === 'near-operation-file' && this._documents.length === 1) {
2147 imports.push(`import * as Operations from './${this.clearExtension(basename(this._documents[0].location))}';`);
2148 }
2149 else {
2150 imports.push(`import * as Operations from '${this.clearExtension(this.config.importDocumentNodeExternallyFrom)}';`);
2151 }
2152 }
2153 break;
2154 }
2155 }
2156 if (!options.excludeFragments && !this.config.globalNamespace) {
2157 const { documentMode, fragmentImports } = this.config;
2158 if (documentMode === DocumentMode.graphQLTag ||
2159 documentMode === DocumentMode.string ||
2160 documentMode === DocumentMode.documentNodeImportFragments) {
2161 imports.push(...fragmentImports.map(fragmentImport => generateFragmentImportStatement(fragmentImport, 'document')));
2162 }
2163 }
2164 return imports;
2165 }
2166 buildOperation(node, documentVariableName, operationType, operationResultType, operationVariablesTypes) {
2167 return null;
2168 }
2169 getDocumentNodeSignature(resultType, variablesTypes, node) {
2170 return `DocumentNode`;
2171 }
2172 OperationDefinition(node) {
2173 if (!node.name || !node.name.value) {
2174 return null;
2175 }
2176 this._collectedOperations.push(node);
2177 const documentVariableName = this.convertName(node, {
2178 suffix: this.config.documentVariableSuffix,
2179 prefix: this.config.documentVariablePrefix,
2180 useTypesPrefix: false,
2181 });
2182 const operationType = pascalCase(node.operation);
2183 const operationTypeSuffix = this.getOperationSuffix(node, operationType);
2184 const operationResultType = this.convertName(node, {
2185 suffix: operationTypeSuffix + this._parsedConfig.operationResultSuffix,
2186 });
2187 const operationVariablesTypes = this.convertName(node, {
2188 suffix: operationTypeSuffix + 'Variables',
2189 });
2190 let documentString = '';
2191 if (this.config.documentMode !== DocumentMode.external) {
2192 const isDocumentNode = this.config.documentMode === DocumentMode.documentNode ||
2193 this.config.documentMode === DocumentMode.documentNodeImportFragments;
2194 documentString = `${this.config.noExport ? '' : 'export'} const ${documentVariableName}${isDocumentNode ? `: ${this.getDocumentNodeSignature(operationResultType, operationVariablesTypes, node)}` : ''} =${this.config.pureMagicComment ? ' /*#__PURE__*/' : ''} ${this._gql(node)};`;
2195 }
2196 const additional = this.buildOperation(node, documentVariableName, operationType, operationResultType, operationVariablesTypes);
2197 return [documentString, additional].filter(a => a).join('\n');
2198 }
2199}
2200
2201function isMetadataFieldName(name) {
2202 return ['__schema', '__type'].includes(name);
2203}
2204const metadataFieldMap = {
2205 __schema: SchemaMetaFieldDef,
2206 __type: TypeMetaFieldDef,
2207};
2208class SelectionSetToObject {
2209 constructor(_processor, _scalars, _schema, _convertName, _getFragmentSuffix, _loadedFragments, _config, _parentSchemaType, _selectionSet) {
2210 this._processor = _processor;
2211 this._scalars = _scalars;
2212 this._schema = _schema;
2213 this._convertName = _convertName;
2214 this._getFragmentSuffix = _getFragmentSuffix;
2215 this._loadedFragments = _loadedFragments;
2216 this._config = _config;
2217 this._parentSchemaType = _parentSchemaType;
2218 this._selectionSet = _selectionSet;
2219 this._primitiveFields = [];
2220 this._primitiveAliasedFields = [];
2221 this._linksFields = [];
2222 this._queriedForTypename = false;
2223 autoBind(this);
2224 }
2225 createNext(parentSchemaType, selectionSet) {
2226 return new SelectionSetToObject(this._processor, this._scalars, this._schema, this._convertName.bind(this), this._getFragmentSuffix.bind(this), this._loadedFragments, this._config, parentSchemaType, selectionSet);
2227 }
2228 /**
2229 * traverse the inline fragment nodes recursively for colleting the selectionSets on each type
2230 */
2231 _collectInlineFragments(parentType, nodes, types) {
2232 if (isListType(parentType) || isNonNullType(parentType)) {
2233 return this._collectInlineFragments(parentType.ofType, nodes, types);
2234 }
2235 else if (isObjectType(parentType)) {
2236 for (const node of nodes) {
2237 const typeOnSchema = node.typeCondition ? this._schema.getType(node.typeCondition.name.value) : parentType;
2238 const { fields, inlines, spreads } = separateSelectionSet(node.selectionSet.selections);
2239 const spreadsUsage = this.buildFragmentSpreadsUsage(spreads);
2240 if (isObjectType(typeOnSchema)) {
2241 this._appendToTypeMap(types, typeOnSchema.name, fields);
2242 this._appendToTypeMap(types, typeOnSchema.name, spreadsUsage[typeOnSchema.name]);
2243 this._collectInlineFragments(typeOnSchema, inlines, types);
2244 }
2245 else if (isInterfaceType(typeOnSchema) && parentType.isTypeOf(typeOnSchema, null, null)) {
2246 this._appendToTypeMap(types, parentType.name, fields);
2247 this._appendToTypeMap(types, parentType.name, spreadsUsage[parentType.name]);
2248 this._collectInlineFragments(typeOnSchema, inlines, types);
2249 }
2250 }
2251 }
2252 else if (isInterfaceType(parentType)) {
2253 const possibleTypes = getPossibleTypes(this._schema, parentType);
2254 for (const node of nodes) {
2255 const schemaType = node.typeCondition ? this._schema.getType(node.typeCondition.name.value) : parentType;
2256 const { fields, inlines, spreads } = separateSelectionSet(node.selectionSet.selections);
2257 const spreadsUsage = this.buildFragmentSpreadsUsage(spreads);
2258 if (isObjectType(schemaType) && possibleTypes.find(possibleType => possibleType.name === schemaType.name)) {
2259 this._appendToTypeMap(types, schemaType.name, fields);
2260 this._appendToTypeMap(types, schemaType.name, spreadsUsage[schemaType.name]);
2261 this._collectInlineFragments(schemaType, inlines, types);
2262 }
2263 else if (isInterfaceType(schemaType) && schemaType.name === parentType.name) {
2264 for (const possibleType of possibleTypes) {
2265 this._appendToTypeMap(types, possibleType.name, fields);
2266 this._appendToTypeMap(types, possibleType.name, spreadsUsage[possibleType.name]);
2267 this._collectInlineFragments(schemaType, inlines, types);
2268 }
2269 }
2270 else {
2271 for (const possibleType of possibleTypes) {
2272 this._appendToTypeMap(types, possibleType.name, fields);
2273 this._appendToTypeMap(types, possibleType.name, spreadsUsage[possibleType.name]);
2274 }
2275 }
2276 }
2277 }
2278 else if (isUnionType(parentType)) {
2279 const possibleTypes = parentType.getTypes();
2280 for (const node of nodes) {
2281 const schemaType = node.typeCondition ? this._schema.getType(node.typeCondition.name.value) : parentType;
2282 const { fields, inlines, spreads } = separateSelectionSet(node.selectionSet.selections);
2283 const spreadsUsage = this.buildFragmentSpreadsUsage(spreads);
2284 if (isObjectType(schemaType) && possibleTypes.find(possibleType => possibleType.name === schemaType.name)) {
2285 this._appendToTypeMap(types, schemaType.name, fields);
2286 this._appendToTypeMap(types, schemaType.name, spreadsUsage[schemaType.name]);
2287 this._collectInlineFragments(schemaType, inlines, types);
2288 }
2289 else if (isInterfaceType(schemaType)) {
2290 const possibleInterfaceTypes = getPossibleTypes(this._schema, schemaType);
2291 for (const possibleType of possibleTypes) {
2292 if (possibleInterfaceTypes.find(possibleInterfaceType => possibleInterfaceType.name === possibleType.name)) {
2293 this._appendToTypeMap(types, possibleType.name, fields);
2294 this._appendToTypeMap(types, possibleType.name, spreadsUsage[possibleType.name]);
2295 this._collectInlineFragments(schemaType, inlines, types);
2296 }
2297 }
2298 }
2299 else {
2300 for (const possibleType of possibleTypes) {
2301 this._appendToTypeMap(types, possibleType.name, fields);
2302 this._appendToTypeMap(types, possibleType.name, spreadsUsage[possibleType.name]);
2303 }
2304 }
2305 }
2306 }
2307 }
2308 _createInlineFragmentForFieldNodes(parentType, fieldNodes) {
2309 return {
2310 kind: Kind.INLINE_FRAGMENT,
2311 typeCondition: {
2312 kind: Kind.NAMED_TYPE,
2313 name: {
2314 kind: Kind.NAME,
2315 value: parentType.name,
2316 },
2317 },
2318 directives: [],
2319 selectionSet: {
2320 kind: Kind.SELECTION_SET,
2321 selections: fieldNodes,
2322 },
2323 };
2324 }
2325 buildFragmentSpreadsUsage(spreads) {
2326 const selectionNodesByTypeName = {};
2327 for (const spread of spreads) {
2328 const fragmentSpreadObject = this._loadedFragments.find(lf => lf.name === spread.name.value);
2329 if (fragmentSpreadObject) {
2330 const schemaType = this._schema.getType(fragmentSpreadObject.onType);
2331 const possibleTypesForFragment = getPossibleTypes(this._schema, schemaType);
2332 for (const possibleType of possibleTypesForFragment) {
2333 const fragmentSuffix = this._getFragmentSuffix(spread.name.value);
2334 const usage = this.buildFragmentTypeName(spread.name.value, fragmentSuffix, possibleTypesForFragment.length === 1 ? null : possibleType.name);
2335 if (!selectionNodesByTypeName[possibleType.name]) {
2336 selectionNodesByTypeName[possibleType.name] = [];
2337 }
2338 selectionNodesByTypeName[possibleType.name].push(usage);
2339 }
2340 }
2341 }
2342 return selectionNodesByTypeName;
2343 }
2344 flattenSelectionSet(selections) {
2345 const selectionNodesByTypeName = new Map();
2346 const inlineFragmentSelections = [];
2347 const fieldNodes = [];
2348 const fragmentSpreads = [];
2349 for (const selection of selections) {
2350 switch (selection.kind) {
2351 case Kind.FIELD:
2352 fieldNodes.push(selection);
2353 break;
2354 case Kind.INLINE_FRAGMENT:
2355 inlineFragmentSelections.push(selection);
2356 break;
2357 case Kind.FRAGMENT_SPREAD:
2358 fragmentSpreads.push(selection);
2359 break;
2360 }
2361 }
2362 if (fieldNodes.length) {
2363 inlineFragmentSelections.push(this._createInlineFragmentForFieldNodes(this._parentSchemaType, fieldNodes));
2364 }
2365 this._collectInlineFragments(this._parentSchemaType, inlineFragmentSelections, selectionNodesByTypeName);
2366 const fragmentsUsage = this.buildFragmentSpreadsUsage(fragmentSpreads);
2367 Object.keys(fragmentsUsage).forEach(typeName => {
2368 this._appendToTypeMap(selectionNodesByTypeName, typeName, fragmentsUsage[typeName]);
2369 });
2370 return selectionNodesByTypeName;
2371 }
2372 _appendToTypeMap(types, typeName, nodes) {
2373 if (!types.has(typeName)) {
2374 types.set(typeName, []);
2375 }
2376 if (nodes && nodes.length > 0) {
2377 types.get(typeName).push(...nodes);
2378 }
2379 }
2380 _buildGroupedSelections() {
2381 if (!this._selectionSet || !this._selectionSet.selections || this._selectionSet.selections.length === 0) {
2382 return {};
2383 }
2384 const selectionNodesByTypeName = this.flattenSelectionSet(this._selectionSet.selections);
2385 const grouped = getPossibleTypes(this._schema, this._parentSchemaType).reduce((prev, type) => {
2386 const typeName = type.name;
2387 const schemaType = this._schema.getType(typeName);
2388 if (!isObjectType(schemaType)) {
2389 throw new TypeError(`Invalid state! Schema type ${typeName} is not a valid GraphQL object!`);
2390 }
2391 const selectionNodes = selectionNodesByTypeName.get(typeName) || [];
2392 if (!prev[typeName]) {
2393 prev[typeName] = [];
2394 }
2395 const transformedSet = this.buildSelectionSetString(schemaType, selectionNodes);
2396 if (transformedSet) {
2397 prev[typeName].push(transformedSet);
2398 }
2399 return prev;
2400 }, {});
2401 return grouped;
2402 }
2403 buildSelectionSetString(parentSchemaType, selectionNodes) {
2404 const primitiveFields = new Map();
2405 const primitiveAliasFields = new Map();
2406 const linkFieldSelectionSets = new Map();
2407 let requireTypename = false;
2408 const fragmentsSpreadUsages = [];
2409 for (const selectionNode of selectionNodes) {
2410 if (typeof selectionNode === 'string') {
2411 fragmentsSpreadUsages.push(selectionNode);
2412 }
2413 else if (selectionNode.kind === 'Field') {
2414 if (!selectionNode.selectionSet) {
2415 if (selectionNode.alias) {
2416 primitiveAliasFields.set(selectionNode.alias.value, selectionNode);
2417 }
2418 else if (selectionNode.name.value === '__typename') {
2419 requireTypename = true;
2420 }
2421 else {
2422 primitiveFields.set(selectionNode.name.value, selectionNode);
2423 }
2424 }
2425 else {
2426 let selectedField = null;
2427 const fields = parentSchemaType.getFields();
2428 selectedField = fields[selectionNode.name.value];
2429 if (isMetadataFieldName(selectionNode.name.value)) {
2430 selectedField = metadataFieldMap[selectionNode.name.value];
2431 }
2432 if (!selectedField) {
2433 continue;
2434 }
2435 const fieldName = getFieldNodeNameValue(selectionNode);
2436 let linkFieldNode = linkFieldSelectionSets.get(fieldName);
2437 if (!linkFieldNode) {
2438 linkFieldNode = {
2439 selectedFieldType: selectedField.type,
2440 field: selectionNode,
2441 };
2442 linkFieldSelectionSets.set(fieldName, linkFieldNode);
2443 }
2444 else {
2445 mergeSelectionSets(linkFieldNode.field.selectionSet, selectionNode.selectionSet);
2446 }
2447 }
2448 }
2449 }
2450 const linkFields = [];
2451 for (const { field, selectedFieldType } of linkFieldSelectionSets.values()) {
2452 const realSelectedFieldType = getBaseType(selectedFieldType);
2453 const selectionSet = this.createNext(realSelectedFieldType, field.selectionSet);
2454 linkFields.push({
2455 alias: field.alias ? this._processor.config.formatNamedField(field.alias.value, selectedFieldType) : undefined,
2456 name: this._processor.config.formatNamedField(field.name.value, selectedFieldType),
2457 type: realSelectedFieldType.name,
2458 selectionSet: this._processor.config.wrapTypeWithModifiers(selectionSet
2459 .transformSelectionSet()
2460 .split(`\n`)
2461 .join(`\n `), selectedFieldType),
2462 });
2463 }
2464 const typeInfoField = this.buildTypeNameField(parentSchemaType, this._config.nonOptionalTypename, this._config.addTypename, requireTypename, this._config.skipTypeNameForRoot);
2465 const transformed = [
2466 ...(typeInfoField ? this._processor.transformTypenameField(typeInfoField.type, typeInfoField.name) : []),
2467 ...this._processor.transformPrimitiveFields(parentSchemaType, Array.from(primitiveFields.values()).map(field => field.name.value)),
2468 ...this._processor.transformAliasesPrimitiveFields(parentSchemaType, Array.from(primitiveAliasFields.values()).map(field => ({
2469 alias: field.alias.value,
2470 fieldName: field.name.value,
2471 }))),
2472 ...this._processor.transformLinkFields(linkFields),
2473 ].filter(Boolean);
2474 const allStrings = transformed.filter(t => typeof t === 'string');
2475 const allObjectsMerged = transformed
2476 .filter(t => typeof t !== 'string')
2477 .map((t) => `${t.name}: ${t.type}`);
2478 let mergedObjectsAsString = null;
2479 if (allObjectsMerged.length > 0) {
2480 mergedObjectsAsString = this._processor.buildFieldsIntoObject(allObjectsMerged);
2481 }
2482 const fields = [...allStrings, mergedObjectsAsString, ...fragmentsSpreadUsages].filter(Boolean);
2483 return this._processor.buildSelectionSetFromStrings(fields);
2484 }
2485 isRootType(type) {
2486 const rootType = [this._schema.getQueryType(), this._schema.getMutationType(), this._schema.getSubscriptionType()]
2487 .filter(Boolean)
2488 .map(t => t.name);
2489 return rootType.includes(type.name);
2490 }
2491 buildTypeNameField(type, nonOptionalTypename = this._config.nonOptionalTypename, addTypename = this._config.addTypename, queriedForTypename = this._queriedForTypename, skipTypeNameForRoot = this._config.skipTypeNameForRoot) {
2492 if (this.isRootType(type) && skipTypeNameForRoot && !queriedForTypename) {
2493 return null;
2494 }
2495 if (nonOptionalTypename || addTypename || queriedForTypename) {
2496 const optionalTypename = !queriedForTypename && !nonOptionalTypename;
2497 return {
2498 name: `${this._processor.config.formatNamedField('__typename')}${optionalTypename ? '?' : ''}`,
2499 type: `'${type.name}'`,
2500 };
2501 }
2502 return null;
2503 }
2504 transformSelectionSet() {
2505 const grouped = this._buildGroupedSelections();
2506 return Object.keys(grouped)
2507 .map(typeName => {
2508 const relevant = grouped[typeName].filter(Boolean);
2509 if (relevant.length === 0) {
2510 return null;
2511 }
2512 else if (relevant.length === 1) {
2513 return relevant[0];
2514 }
2515 else {
2516 return `( ${relevant.join(' & ')} )`;
2517 }
2518 })
2519 .filter(Boolean)
2520 .join(' | ');
2521 }
2522 transformFragmentSelectionSetToTypes(fragmentName, fragmentSuffix, declarationBlockConfig) {
2523 const grouped = this._buildGroupedSelections();
2524 const subTypes = Object.keys(grouped)
2525 .map(typeName => {
2526 const possibleFields = grouped[typeName].filter(Boolean);
2527 if (possibleFields.length === 0) {
2528 return null;
2529 }
2530 const declarationName = this.buildFragmentTypeName(fragmentName, fragmentSuffix, typeName);
2531 return { name: declarationName, content: possibleFields.join(' & ') };
2532 })
2533 .filter(Boolean);
2534 if (subTypes.length === 1) {
2535 return new DeclarationBlock(declarationBlockConfig)
2536 .export()
2537 .asKind('type')
2538 .withName(this.buildFragmentTypeName(fragmentName, fragmentSuffix))
2539 .withContent(subTypes[0].content).string;
2540 }
2541 return [
2542 ...subTypes.map(t => new DeclarationBlock(declarationBlockConfig)
2543 .export(this._config.exportFragmentSpreadSubTypes)
2544 .asKind('type')
2545 .withName(t.name)
2546 .withContent(t.content).string),
2547 new DeclarationBlock(declarationBlockConfig)
2548 .export()
2549 .asKind('type')
2550 .withName(this.buildFragmentTypeName(fragmentName, fragmentSuffix))
2551 .withContent(subTypes.map(t => t.name).join(' | ')).string,
2552 ].join('\n');
2553 }
2554 buildFragmentTypeName(name, suffix, typeName = '') {
2555 return this._convertName(name, {
2556 useTypesPrefix: true,
2557 suffix: typeName ? `_${typeName}_${suffix}` : suffix,
2558 });
2559 }
2560}
2561
2562class BaseSelectionSetProcessor {
2563 constructor(config) {
2564 this.config = config;
2565 }
2566 buildFieldsIntoObject(allObjectsMerged) {
2567 return `{ ${allObjectsMerged.join(', ')} }`;
2568 }
2569 buildSelectionSetFromStrings(pieces) {
2570 if (pieces.length === 0) {
2571 return null;
2572 }
2573 else if (pieces.length === 1) {
2574 return pieces[0];
2575 }
2576 else {
2577 return `(\n ${pieces.join(`\n & `)}\n)`;
2578 }
2579 }
2580 transformPrimitiveFields(schemaType, fields) {
2581 throw new Error(`Please override "transformPrimitiveFields" as part of your BaseSelectionSetProcessor implementation!`);
2582 }
2583 transformAliasesPrimitiveFields(schemaType, fields) {
2584 throw new Error(`Please override "transformAliasesPrimitiveFields" as part of your BaseSelectionSetProcessor implementation!`);
2585 }
2586 transformLinkFields(fields) {
2587 throw new Error(`Please override "transformLinkFields" as part of your BaseSelectionSetProcessor implementation!`);
2588 }
2589 transformTypenameField(type, name) {
2590 throw new Error(`Please override "transformTypenameField" as part of your BaseSelectionSetProcessor implementation!`);
2591 }
2592}
2593
2594class PreResolveTypesProcessor extends BaseSelectionSetProcessor {
2595 transformTypenameField(type, name) {
2596 return [
2597 {
2598 type,
2599 name,
2600 },
2601 ];
2602 }
2603 transformPrimitiveFields(schemaType, fields) {
2604 if (fields.length === 0) {
2605 return [];
2606 }
2607 return fields.map(field => {
2608 const fieldObj = schemaType.getFields()[field];
2609 const baseType = getBaseType(fieldObj.type);
2610 let typeToUse = baseType.name;
2611 if (isEnumType(baseType)) {
2612 typeToUse =
2613 (this.config.namespacedImportName ? `${this.config.namespacedImportName}.` : '') +
2614 this.config.convertName(baseType.name, { useTypesPrefix: this.config.enumPrefix });
2615 }
2616 else if (this.config.scalars[baseType.name]) {
2617 typeToUse = this.config.scalars[baseType.name];
2618 }
2619 const name = this.config.formatNamedField(field, fieldObj.type);
2620 const wrappedType = this.config.wrapTypeWithModifiers(typeToUse, fieldObj.type);
2621 return {
2622 name,
2623 type: wrappedType,
2624 };
2625 });
2626 }
2627 transformAliasesPrimitiveFields(schemaType, fields) {
2628 if (fields.length === 0) {
2629 return [];
2630 }
2631 return fields.map(aliasedField => {
2632 if (aliasedField.fieldName === '__typename') {
2633 const name = this.config.formatNamedField(aliasedField.alias, null);
2634 return {
2635 name,
2636 type: `'${schemaType.name}'`,
2637 };
2638 }
2639 else {
2640 const fieldObj = schemaType.getFields()[aliasedField.fieldName];
2641 const baseType = getBaseType(fieldObj.type);
2642 let typeToUse = this.config.scalars[baseType.name] || baseType.name;
2643 if (isEnumType(baseType)) {
2644 typeToUse =
2645 (this.config.namespacedImportName ? `${this.config.namespacedImportName}.` : '') +
2646 this.config.convertName(baseType.name, { useTypesPrefix: this.config.enumPrefix });
2647 }
2648 const name = this.config.formatNamedField(aliasedField.alias, fieldObj.type);
2649 const wrappedType = this.config.wrapTypeWithModifiers(typeToUse, fieldObj.type);
2650 return {
2651 name,
2652 type: wrappedType,
2653 };
2654 }
2655 });
2656 }
2657 transformLinkFields(fields) {
2658 if (fields.length === 0) {
2659 return [];
2660 }
2661 return fields.map(field => ({
2662 name: field.alias || field.name,
2663 type: field.selectionSet,
2664 }));
2665 }
2666}
2667
2668function optimizeOperations(schema, documents, options) {
2669 const newDocuments = optimizeDocuments(schema, documents.map(s => s.document), options);
2670 return newDocuments.map(document => ({
2671 location: 'optimized by relay',
2672 document,
2673 }));
2674}
2675
2676export { 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, buildScalars, clearExtension, convertFactory, convertNameParts, fixLocalFilePath, generateFragmentImportStatement, generateImportStatement, getBaseTypeNode, getConfigValue, getFieldNodeNameValue, getPossibleTypes, getRootTypeNames, indent, indentMultiline, isExternalMapper, isExternalMapperType, isRootType, mergeSelectionSets, normalizeAvoidOptionals, normalizeDeclarationKind, optimizeOperations, parseEnumValues, parseMapper, quoteIfNeeded, resolveImportSource, resolveRelativeImport, separateSelectionSet, stripMapperTypeInterpolation, transformComment, transformMappers, wrapTypeWithModifiers, wrapWithSingleQuotes };
2677//# sourceMappingURL=index.esm.js.map