UNPKG

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