UNPKG

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