UNPKG

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