UNPKG

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