UNPKG

148 kBJavaScriptView Raw
1import { Kind, isScalarType, isListType, isNonNullType, isObjectType, isAbstractType, 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 else if (array.length === 1) {
194 return array[0];
195 }
196 else {
197 return `(${array.join(joinWith)})`;
198 }
199}
200function block(array) {
201 return array && array.length !== 0 ? '{\n' + array.join('\n') + '\n}' : '';
202}
203function wrapWithSingleQuotes(value, skipNumericCheck = false) {
204 if (skipNumericCheck) {
205 if (typeof value === 'number') {
206 return `${value}`;
207 }
208 else {
209 return `'${value}'`;
210 }
211 }
212 if (typeof value === 'number' ||
213 (typeof value === 'string' && !isNaN(parseInt(value)) && parseFloat(value).toString() === value)) {
214 return `${value}`;
215 }
216 return `'${value}'`;
217}
218function breakLine(str) {
219 return str + '\n';
220}
221function indent(str, count = 1) {
222 return new Array(count).fill(' ').join('') + str;
223}
224function indentMultiline(str, count = 1) {
225 const indentation = new Array(count).fill(' ').join('');
226 const replaceWith = '\n' + indentation;
227 return indentation + str.replace(/\n/g, replaceWith);
228}
229function transformComment(comment, indentLevel = 0, disabled = false) {
230 if (!comment || comment === '' || disabled) {
231 return '';
232 }
233 if (isStringValueNode(comment)) {
234 comment = comment.value;
235 }
236 comment = comment.split('*/').join('*\\/');
237 let lines = comment.split('\n');
238 if (lines.length === 1) {
239 return indent(`/** ${lines[0]} */\n`, indentLevel);
240 }
241 lines = ['/**', ...lines.map(line => ` * ${line}`), ' */\n'];
242 return stripTrailingSpaces(lines.map(line => indent(line, indentLevel)).join('\n'));
243}
244class DeclarationBlock {
245 constructor(_config) {
246 this._config = _config;
247 this._decorator = null;
248 this._export = false;
249 this._name = null;
250 this._kind = null;
251 this._methodName = null;
252 this._content = null;
253 this._block = null;
254 this._nameGenerics = null;
255 this._comment = null;
256 this._ignoreBlockWrapper = false;
257 this._config = {
258 blockWrapper: '',
259 blockTransformer: block => block,
260 enumNameValueSeparator: ':',
261 ...this._config,
262 };
263 }
264 withDecorator(decorator) {
265 this._decorator = decorator;
266 return this;
267 }
268 export(exp = true) {
269 if (!this._config.ignoreExport) {
270 this._export = exp;
271 }
272 return this;
273 }
274 asKind(kind) {
275 this._kind = kind;
276 return this;
277 }
278 withComment(comment, disabled = false) {
279 const nonEmptyComment = isStringValueNode(comment) ? !!comment.value : !!comment;
280 if (nonEmptyComment && !disabled) {
281 this._comment = transformComment(comment, 0);
282 }
283 return this;
284 }
285 withMethodCall(methodName, ignoreBlockWrapper = false) {
286 this._methodName = methodName;
287 this._ignoreBlockWrapper = ignoreBlockWrapper;
288 return this;
289 }
290 withBlock(block) {
291 this._block = block;
292 return this;
293 }
294 withContent(content) {
295 this._content = content;
296 return this;
297 }
298 withName(name, generics = null) {
299 this._name = name;
300 this._nameGenerics = generics;
301 return this;
302 }
303 get string() {
304 let result = '';
305 if (this._decorator) {
306 result += this._decorator + '\n';
307 }
308 if (this._export) {
309 result += 'export ';
310 }
311 if (this._kind) {
312 let extra = '';
313 let name = '';
314 if (['type', 'const', 'var', 'let'].includes(this._kind)) {
315 extra = '= ';
316 }
317 if (this._name) {
318 name = this._name + (this._nameGenerics || '') + ' ';
319 }
320 result += this._kind + ' ' + name + extra;
321 }
322 if (this._block) {
323 if (this._content) {
324 result += this._content;
325 }
326 const blockWrapper = this._ignoreBlockWrapper ? '' : this._config.blockWrapper;
327 const before = '{' + blockWrapper;
328 const after = blockWrapper + '}';
329 const block = [before, this._block, after].filter(val => !!val).join('\n');
330 if (this._methodName) {
331 result += `${this._methodName}(${this._config.blockTransformer(block)})`;
332 }
333 else {
334 result += this._config.blockTransformer(block);
335 }
336 }
337 else if (this._content) {
338 result += this._content;
339 }
340 else if (this._kind) {
341 result += this._config.blockTransformer('{}');
342 }
343 return stripTrailingSpaces((this._comment ? this._comment : '') +
344 result +
345 (this._kind === 'interface' || this._kind === 'enum' || this._kind === 'namespace' || this._kind === 'function'
346 ? ''
347 : ';') +
348 '\n');
349 }
350}
351function getBaseTypeNode(typeNode) {
352 if (typeNode.kind === Kind.LIST_TYPE || typeNode.kind === Kind.NON_NULL_TYPE) {
353 return getBaseTypeNode(typeNode.type);
354 }
355 return typeNode;
356}
357function convertNameParts(str, func, removeUnderscore = false) {
358 if (removeUnderscore) {
359 return func(str);
360 }
361 return str
362 .split('_')
363 .map(s => func(s))
364 .join('_');
365}
366function buildScalarsFromConfig(schema, config, defaultScalarsMapping = DEFAULT_SCALARS, defaultScalarType = 'any') {
367 return buildScalars(schema, config.scalars, defaultScalarsMapping, config.strictScalars ? null : config.defaultScalarType || defaultScalarType);
368}
369function buildScalars(schema, scalarsMapping, defaultScalarsMapping = DEFAULT_SCALARS, defaultScalarType = 'any') {
370 const result = {};
371 Object.keys(defaultScalarsMapping).forEach(name => {
372 result[name] = parseMapper(defaultScalarsMapping[name]);
373 });
374 if (schema) {
375 const typeMap = schema.getTypeMap();
376 Object.keys(typeMap)
377 .map(typeName => typeMap[typeName])
378 .filter(type => isScalarType(type))
379 .map((scalarType) => {
380 var _a;
381 const { name } = scalarType;
382 if (typeof scalarsMapping === 'string') {
383 const value = parseMapper(scalarsMapping + '#' + name, name);
384 result[name] = value;
385 }
386 else if (scalarsMapping && typeof scalarsMapping[name] === 'string') {
387 const value = parseMapper(scalarsMapping[name], name);
388 result[name] = value;
389 }
390 else if (scalarsMapping && scalarsMapping[name]) {
391 result[name] = {
392 isExternal: false,
393 type: JSON.stringify(scalarsMapping[name]),
394 };
395 }
396 else if ((_a = scalarType.extensions) === null || _a === void 0 ? void 0 : _a.codegenScalarType) {
397 result[name] = {
398 isExternal: false,
399 type: scalarType.extensions.codegenScalarType,
400 };
401 }
402 else if (!defaultScalarsMapping[name]) {
403 if (defaultScalarType === null) {
404 throw new Error(`Unknown scalar type ${name}. Please override it using the "scalars" configuration field!`);
405 }
406 result[name] = {
407 isExternal: false,
408 type: defaultScalarType,
409 };
410 }
411 });
412 }
413 else if (scalarsMapping) {
414 if (typeof scalarsMapping === 'string') {
415 throw new Error('Cannot use string scalars mapping when building without a schema');
416 }
417 Object.keys(scalarsMapping).forEach(name => {
418 if (typeof scalarsMapping[name] === 'string') {
419 const value = parseMapper(scalarsMapping[name], name);
420 result[name] = value;
421 }
422 else {
423 result[name] = {
424 isExternal: false,
425 type: JSON.stringify(scalarsMapping[name]),
426 };
427 }
428 });
429 }
430 return result;
431}
432function isStringValueNode(node) {
433 return node && typeof node === 'object' && node.kind === Kind.STRING;
434}
435// will be removed on next release because tools already has it
436function getRootTypeNames(schema) {
437 return [schema.getQueryType(), schema.getMutationType(), schema.getSubscriptionType()]
438 .filter(t => t)
439 .map(t => t.name);
440}
441function stripMapperTypeInterpolation(identifier) {
442 return identifier.trim().replace(/<{.*}>/, '');
443}
444const OMIT_TYPE = 'export type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;';
445const REQUIRE_FIELDS_TYPE = `export type RequireFields<T, K extends keyof T> = Omit<T, K> & { [P in K]-?: NonNullable<T[P]> };`;
446/**
447 * merge selection sets into a new selection set without mutating the inputs.
448 */
449function mergeSelectionSets(selectionSet1, selectionSet2) {
450 const newSelections = [...selectionSet1.selections];
451 for (let selection2 of selectionSet2.selections) {
452 if (selection2.kind === 'FragmentSpread' || selection2.kind === 'InlineFragment') {
453 newSelections.push(selection2);
454 continue;
455 }
456 if (selection2.kind !== 'Field') {
457 throw new TypeError('Invalid state.');
458 }
459 const match = newSelections.find(selection1 => selection1.kind === 'Field' &&
460 getFieldNodeNameValue(selection1) === getFieldNodeNameValue(selection2));
461 if (match) {
462 // recursively merge all selection sets
463 if (match.kind === 'Field' && match.selectionSet && selection2.selectionSet) {
464 selection2 = {
465 ...selection2,
466 selectionSet: mergeSelectionSets(match.selectionSet, selection2.selectionSet),
467 };
468 }
469 }
470 newSelections.push(selection2);
471 }
472 return {
473 kind: Kind.SELECTION_SET,
474 selections: newSelections,
475 };
476}
477const getFieldNodeNameValue = (node) => {
478 return (node.alias || node.name).value;
479};
480function separateSelectionSet(selections) {
481 return {
482 fields: selections.filter(s => s.kind === Kind.FIELD),
483 inlines: selections.filter(s => s.kind === Kind.INLINE_FRAGMENT),
484 spreads: selections.filter(s => s.kind === Kind.FRAGMENT_SPREAD),
485 };
486}
487function getPossibleTypes(schema, type) {
488 if (isListType(type) || isNonNullType(type)) {
489 return getPossibleTypes(schema, type.ofType);
490 }
491 else if (isObjectType(type)) {
492 return [type];
493 }
494 else if (isAbstractType(type)) {
495 return schema.getPossibleTypes(type);
496 }
497 return [];
498}
499function hasConditionalDirectives(field) {
500 var _a;
501 const CONDITIONAL_DIRECTIVES = ['skip', 'include'];
502 return (_a = field.directives) === null || _a === void 0 ? void 0 : _a.some(directive => CONDITIONAL_DIRECTIVES.includes(directive.name.value));
503}
504function wrapTypeWithModifiers(baseType, type, options) {
505 let currentType = type;
506 const modifiers = [];
507 while (currentType) {
508 if (isNonNullType(currentType)) {
509 currentType = currentType.ofType;
510 }
511 else {
512 modifiers.push(options.wrapOptional);
513 }
514 if (isListType(currentType)) {
515 modifiers.push(options.wrapArray);
516 currentType = currentType.ofType;
517 }
518 else {
519 break;
520 }
521 }
522 return modifiers.reduceRight((result, modifier) => modifier(result), baseType);
523}
524function removeDescription(nodes) {
525 return nodes.map(node => ({ ...node, description: undefined }));
526}
527function wrapTypeNodeWithModifiers(baseType, typeNode) {
528 switch (typeNode.kind) {
529 case Kind.NAMED_TYPE: {
530 return `Maybe<${baseType}>`;
531 }
532 case Kind.NON_NULL_TYPE: {
533 const innerType = wrapTypeNodeWithModifiers(baseType, typeNode.type);
534 return clearOptional(innerType);
535 }
536 case Kind.LIST_TYPE: {
537 const innerType = wrapTypeNodeWithModifiers(baseType, typeNode.type);
538 return `Maybe<Array<${innerType}>>`;
539 }
540 }
541}
542function clearOptional(str) {
543 const rgx = new RegExp(`^Maybe<(.*?)>$`, 'i');
544 if (str.startsWith(`Maybe`)) {
545 return str.replace(rgx, '$1');
546 }
547 return str;
548}
549function stripTrailingSpaces(str) {
550 return str.replace(/ +\n/g, '\n');
551}
552
553function getKind(node) {
554 if (typeof node === 'string') {
555 return 'typeNames';
556 }
557 if (['EnumValueDefinition', 'EnumValue'].includes(node.kind)) {
558 return 'enumValues';
559 }
560 return 'typeNames';
561}
562function getName(node) {
563 if (node == null) {
564 return undefined;
565 }
566 if (typeof node === 'string') {
567 return node;
568 }
569 switch (node.kind) {
570 case 'OperationDefinition':
571 case 'Variable':
572 case 'Argument':
573 case 'FragmentSpread':
574 case 'FragmentDefinition':
575 case 'ObjectField':
576 case 'Directive':
577 case 'NamedType':
578 case 'ScalarTypeDefinition':
579 case 'ObjectTypeDefinition':
580 case 'FieldDefinition':
581 case 'InputValueDefinition':
582 case 'InterfaceTypeDefinition':
583 case 'UnionTypeDefinition':
584 case 'EnumTypeDefinition':
585 case 'EnumValueDefinition':
586 case 'InputObjectTypeDefinition':
587 case 'DirectiveDefinition': {
588 return getName(node.name);
589 }
590 case 'Name': {
591 return node.value;
592 }
593 case 'Field': {
594 return getName(node.alias || node.name);
595 }
596 case 'VariableDefinition': {
597 return getName(node.variable);
598 }
599 }
600 return undefined;
601}
602function convertFactory(config) {
603 function resolveConventionName(type) {
604 if (!config.namingConvention) {
605 return (str, opts = {}) => {
606 return convertNameParts(str, pascalCase, getConfigValue((opts || {}).transformUnderscore, false));
607 };
608 }
609 if (typeof config.namingConvention === 'string') {
610 if (config.namingConvention === 'keep') {
611 return str => str;
612 }
613 return (str, opts = {}) => {
614 return convertNameParts(str, resolveExternalModuleAndFn(config.namingConvention), getConfigValue((opts || {}).transformUnderscore, false));
615 };
616 }
617 if (typeof config.namingConvention === 'function') {
618 return (str, opts = {}) => {
619 return convertNameParts(str, config.namingConvention, getConfigValue((opts || {}).transformUnderscore, false));
620 };
621 }
622 if (typeof config.namingConvention === 'object' && config.namingConvention[type] === 'keep') {
623 return str => str;
624 }
625 if (typeof config.namingConvention === 'object') {
626 if (!config.namingConvention[type]) {
627 return (str, opts = {}) => {
628 const transformUnderscore = config.namingConvention.transformUnderscore || (opts || {}).transformUnderscore;
629 return convertNameParts(str, pascalCase, getConfigValue(transformUnderscore, false));
630 };
631 }
632 return (str, opts = {}) => {
633 return convertNameParts(str, resolveExternalModuleAndFn(config.namingConvention[type]), getConfigValue((opts || {}).transformUnderscore, true));
634 };
635 }
636 return config.namingConvention[type];
637 }
638 return (node, opts) => {
639 const prefix = opts && opts.prefix;
640 const suffix = opts && opts.suffix;
641 const kind = getKind(node);
642 const str = [prefix || '', getName(node), suffix || ''].join('');
643 return resolveConventionName(kind)(str, opts);
644 };
645}
646
647function escapeString(str) {
648 return str.replace(/\\/g, '\\\\').replace(/\n/g, '\\n').replace(/'/g, "\\'");
649}
650function parseEnumValues({ schema, mapOrStr = {}, ignoreEnumValuesFromSchema, }) {
651 const allTypes = schema.getTypeMap();
652 const allEnums = Object.keys(allTypes).filter(t => isEnumType(allTypes[t]));
653 if (typeof mapOrStr === 'object') {
654 if (!ignoreEnumValuesFromSchema) {
655 for (const enumTypeName of allEnums) {
656 const enumType = schema.getType(enumTypeName);
657 for (const { name, value } of enumType.getValues()) {
658 if (value && value !== name) {
659 mapOrStr[enumTypeName] = mapOrStr[enumTypeName] || {};
660 if (typeof mapOrStr[enumTypeName] !== 'string' && !mapOrStr[enumTypeName][name]) {
661 mapOrStr[enumTypeName][name] = typeof value === 'string' ? escapeString(value) : value;
662 }
663 }
664 }
665 }
666 }
667 const invalidMappings = Object.keys(mapOrStr).filter(gqlName => !allEnums.includes(gqlName));
668 if (invalidMappings.length > 0) {
669 throw new DetailedError(`Invalid 'enumValues' mapping!`, `The following types does not exist in your GraphQL schema: ${invalidMappings.join(', ')}`);
670 }
671 return Object.keys(mapOrStr).reduce((prev, gqlIdentifier) => {
672 const pointer = mapOrStr[gqlIdentifier];
673 if (typeof pointer === 'string') {
674 const mapper = parseMapper(pointer, gqlIdentifier);
675 return {
676 ...prev,
677 [gqlIdentifier]: {
678 isDefault: mapper.isExternal && mapper.default,
679 typeIdentifier: gqlIdentifier,
680 sourceFile: mapper.isExternal ? mapper.source : null,
681 sourceIdentifier: mapper.type,
682 importIdentifier: mapper.isExternal ? mapper.import : null,
683 mappedValues: null,
684 },
685 };
686 }
687 else if (typeof pointer === 'object') {
688 return {
689 ...prev,
690 [gqlIdentifier]: {
691 isDefault: false,
692 typeIdentifier: gqlIdentifier,
693 sourceFile: null,
694 sourceIdentifier: null,
695 importIdentifier: null,
696 mappedValues: pointer,
697 },
698 };
699 }
700 else {
701 throw new DetailedError(`Invalid "enumValues" configuration`, `Enum "${gqlIdentifier}": expected string or object (with enum values mapping)`);
702 }
703 }, {});
704 }
705 else if (typeof mapOrStr === 'string') {
706 return allEnums
707 .filter(enumName => !enumName.startsWith('__'))
708 .reduce((prev, enumName) => {
709 return {
710 ...prev,
711 [enumName]: {
712 isDefault: false,
713 typeIdentifier: enumName,
714 sourceFile: mapOrStr,
715 sourceIdentifier: enumName,
716 importIdentifier: enumName,
717 mappedValues: null,
718 },
719 };
720 }, {});
721 }
722 return {};
723}
724
725const DEFAULT_DECLARATION_KINDS = {
726 directive: 'type',
727 scalar: 'type',
728 input: 'type',
729 type: 'type',
730 interface: 'type',
731 arguments: 'type',
732};
733function normalizeDeclarationKind(declarationKind) {
734 if (typeof declarationKind === 'string') {
735 return {
736 directive: declarationKind,
737 scalar: declarationKind,
738 input: declarationKind,
739 type: declarationKind,
740 interface: declarationKind,
741 arguments: declarationKind,
742 };
743 }
744 return {
745 ...DEFAULT_DECLARATION_KINDS,
746 ...declarationKind,
747 };
748}
749
750const DEFAULT_AVOID_OPTIONALS = {
751 object: false,
752 inputValue: false,
753 field: false,
754 defaultValue: false,
755 resolvers: false,
756};
757function normalizeAvoidOptionals(avoidOptionals) {
758 if (typeof avoidOptionals === 'boolean') {
759 return {
760 object: avoidOptionals,
761 inputValue: avoidOptionals,
762 field: avoidOptionals,
763 defaultValue: avoidOptionals,
764 resolvers: avoidOptionals,
765 };
766 }
767 return {
768 ...DEFAULT_AVOID_OPTIONALS,
769 ...avoidOptionals,
770 };
771}
772
773function generateFragmentImportStatement(statement, kind) {
774 const { importSource: fragmentImportSource, ...rest } = statement;
775 const { identifiers, path, namespace } = fragmentImportSource;
776 const importSource = {
777 identifiers: identifiers
778 .filter(fragmentImport => kind === 'both' || kind === fragmentImport.kind)
779 .map(({ name }) => name),
780 path,
781 namespace,
782 };
783 return generateImportStatement({
784 importSource,
785 ...rest,
786 typesImport: kind === 'type' ? statement.typesImport : false,
787 });
788}
789function generateImportStatement(statement) {
790 const { baseDir, importSource, outputPath, typesImport } = statement;
791 const importPath = resolveImportPath(baseDir, outputPath, importSource.path);
792 const importNames = importSource.identifiers && importSource.identifiers.length
793 ? `{ ${Array.from(new Set(importSource.identifiers)).join(', ')} }`
794 : '*';
795 const importAlias = importSource.namespace ? ` as ${importSource.namespace}` : '';
796 const importStatement = typesImport ? 'import type' : 'import';
797 return `${importStatement} ${importNames}${importAlias} from '${importPath}';${importAlias ? '\n' : ''}`;
798}
799function resolveImportPath(baseDir, outputPath, sourcePath) {
800 const shouldAbsolute = !sourcePath.startsWith('~');
801 if (shouldAbsolute) {
802 const absGeneratedFilePath = resolve(baseDir, outputPath);
803 const absImportFilePath = resolve(baseDir, sourcePath);
804 return resolveRelativeImport(absGeneratedFilePath, absImportFilePath);
805 }
806 else {
807 return sourcePath.replace(`~`, '');
808 }
809}
810function resolveRelativeImport(from, to) {
811 if (!isAbsolute(from)) {
812 throw new Error(`Argument 'from' must be an absolute path, '${from}' given.`);
813 }
814 if (!isAbsolute(to)) {
815 throw new Error(`Argument 'to' must be an absolute path, '${to}' given.`);
816 }
817 return fixLocalFilePath(clearExtension(relative(dirname(from), to)));
818}
819function resolveImportSource(source) {
820 return typeof source === 'string' ? { path: source } : source;
821}
822function clearExtension(path) {
823 const parsedPath = parse(path);
824 return join(parsedPath.dir, parsedPath.name).replace(/\\/g, '/');
825}
826function fixLocalFilePath(path) {
827 return !path.startsWith('..') ? `./${path}` : path;
828}
829
830class BaseVisitor {
831 constructor(rawConfig, additionalConfig) {
832 var _a;
833 this._declarationBlockConfig = {};
834 this._parsedConfig = {
835 convert: convertFactory(rawConfig),
836 typesPrefix: rawConfig.typesPrefix || '',
837 typesSuffix: rawConfig.typesSuffix || '',
838 externalFragments: rawConfig.externalFragments || [],
839 fragmentImports: rawConfig.fragmentImports || [],
840 addTypename: !rawConfig.skipTypename,
841 nonOptionalTypename: !!rawConfig.nonOptionalTypename,
842 useTypeImports: !!rawConfig.useTypeImports,
843 dedupeFragments: !!rawConfig.dedupeFragments,
844 allowEnumStringTypes: !!rawConfig.allowEnumStringTypes,
845 inlineFragmentTypes: (_a = rawConfig.inlineFragmentTypes) !== null && _a !== void 0 ? _a : 'inline',
846 ...(additionalConfig || {}),
847 };
848 this.scalars = {};
849 Object.keys(this.config.scalars || {}).forEach(key => {
850 this.scalars[key] = this.config.scalars[key].type;
851 });
852 autoBind(this);
853 }
854 getVisitorKindContextFromAncestors(ancestors) {
855 if (!ancestors) {
856 return [];
857 }
858 return ancestors.map(t => t.kind).filter(Boolean);
859 }
860 get config() {
861 return this._parsedConfig;
862 }
863 convertName(node, options) {
864 const useTypesPrefix = typeof (options && options.useTypesPrefix) === 'boolean' ? options.useTypesPrefix : true;
865 const useTypesSuffix = typeof (options && options.useTypesSuffix) === 'boolean' ? options.useTypesSuffix : true;
866 let convertedName = '';
867 if (useTypesPrefix) {
868 convertedName += this.config.typesPrefix;
869 }
870 convertedName += this.config.convert(node, options);
871 if (useTypesSuffix) {
872 convertedName += this.config.typesSuffix;
873 }
874 return convertedName;
875 }
876 getOperationSuffix(node, operationType) {
877 const { omitOperationSuffix = false, dedupeOperationSuffix = false } = this.config;
878 const operationName = typeof node === 'string' ? node : node.name ? node.name.value : '';
879 return omitOperationSuffix
880 ? ''
881 : dedupeOperationSuffix && operationName.toLowerCase().endsWith(operationType.toLowerCase())
882 ? ''
883 : operationType;
884 }
885 getFragmentSuffix(node) {
886 return this.getOperationSuffix(node, 'Fragment');
887 }
888 getFragmentName(node) {
889 return this.convertName(node, {
890 suffix: this.getFragmentSuffix(node),
891 useTypesPrefix: false,
892 });
893 }
894 getFragmentVariableName(node) {
895 const { omitOperationSuffix = false, dedupeOperationSuffix = false, fragmentVariableSuffix = 'FragmentDoc', fragmentVariablePrefix = '', } = this.config;
896 const fragmentName = typeof node === 'string' ? node : node.name.value;
897 const suffix = omitOperationSuffix
898 ? ''
899 : dedupeOperationSuffix &&
900 fragmentName.toLowerCase().endsWith('fragment') &&
901 fragmentVariableSuffix.toLowerCase().startsWith('fragment')
902 ? fragmentVariableSuffix.substring('fragment'.length)
903 : fragmentVariableSuffix;
904 return this.convertName(node, {
905 prefix: fragmentVariablePrefix,
906 suffix,
907 useTypesPrefix: false,
908 });
909 }
910 getPunctuation(_declarationKind) {
911 return '';
912 }
913}
914
915class OperationVariablesToObject {
916 constructor(_scalars, _convertName, _namespacedImportName = null, _enumNames = [], _enumPrefix = true, _enumValues = {}, _applyCoercion = false, _directiveArgumentAndInputFieldMappings = {}) {
917 this._scalars = _scalars;
918 this._convertName = _convertName;
919 this._namespacedImportName = _namespacedImportName;
920 this._enumNames = _enumNames;
921 this._enumPrefix = _enumPrefix;
922 this._enumValues = _enumValues;
923 this._applyCoercion = _applyCoercion;
924 this._directiveArgumentAndInputFieldMappings = _directiveArgumentAndInputFieldMappings;
925 autoBind(this);
926 }
927 getName(node) {
928 if (node.name) {
929 if (typeof node.name === 'string') {
930 return node.name;
931 }
932 return node.name.value;
933 }
934 else if (node.variable) {
935 return node.variable.name.value;
936 }
937 return null;
938 }
939 transform(variablesNode) {
940 if (!variablesNode || variablesNode.length === 0) {
941 return null;
942 }
943 return (variablesNode.map(variable => indent(this.transformVariable(variable))).join(`${this.getPunctuation()}\n`) +
944 this.getPunctuation());
945 }
946 getScalar(name) {
947 const prefix = this._namespacedImportName ? `${this._namespacedImportName}.` : '';
948 return `${prefix}Scalars['${name}']`;
949 }
950 getDirectiveMapping(name) {
951 return `DirectiveArgumentAndInputFieldMappings['${name}']`;
952 }
953 getDirectiveOverrideType(directives) {
954 if (!this._directiveArgumentAndInputFieldMappings)
955 return null;
956 const type = directives
957 .map(directive => {
958 const directiveName = directive.name.value;
959 if (this._directiveArgumentAndInputFieldMappings[directiveName]) {
960 return this.getDirectiveMapping(directiveName);
961 }
962 return null;
963 })
964 .reverse()
965 .find(a => !!a);
966 return type || null;
967 }
968 transformVariable(variable) {
969 let typeValue = null;
970 const prefix = this._namespacedImportName ? `${this._namespacedImportName}.` : '';
971 if (typeof variable.type === 'string') {
972 typeValue = variable.type;
973 }
974 else {
975 const baseType = getBaseTypeNode(variable.type);
976 const overrideType = variable.directives ? this.getDirectiveOverrideType(variable.directives) : null;
977 const typeName = baseType.name.value;
978 if (overrideType) {
979 typeValue = overrideType;
980 }
981 else if (this._scalars[typeName]) {
982 typeValue = this.getScalar(typeName);
983 }
984 else if (this._enumValues[typeName] && this._enumValues[typeName].sourceFile) {
985 typeValue = this._enumValues[typeName].typeIdentifier || this._enumValues[typeName].sourceIdentifier;
986 }
987 else {
988 typeValue = `${prefix}${this._convertName(baseType, {
989 useTypesPrefix: this._enumNames.includes(typeName) ? this._enumPrefix : true,
990 })}`;
991 }
992 }
993 const fieldName = this.getName(variable);
994 const fieldType = this.wrapAstTypeWithModifiers(typeValue, variable.type, this._applyCoercion);
995 const hasDefaultValue = variable.defaultValue != null && typeof variable.defaultValue !== 'undefined';
996 const isNonNullType = variable.type.kind === Kind.NON_NULL_TYPE;
997 const formattedFieldString = this.formatFieldString(fieldName, isNonNullType, hasDefaultValue);
998 const formattedTypeString = this.formatTypeString(fieldType, isNonNullType, hasDefaultValue);
999 return `${formattedFieldString}: ${formattedTypeString}`;
1000 }
1001 wrapAstTypeWithModifiers(_baseType, _typeNode, _applyCoercion) {
1002 throw new Error(`You must override "wrapAstTypeWithModifiers" of OperationVariablesToObject!`);
1003 }
1004 formatFieldString(fieldName, isNonNullType, _hasDefaultValue) {
1005 return fieldName;
1006 }
1007 formatTypeString(fieldType, isNonNullType, hasDefaultValue) {
1008 const prefix = this._namespacedImportName ? `${this._namespacedImportName}.` : '';
1009 if (hasDefaultValue) {
1010 return `${prefix}Maybe<${fieldType}>`;
1011 }
1012 return fieldType;
1013 }
1014 getPunctuation() {
1015 return ',';
1016 }
1017}
1018
1019class BaseTypesVisitor extends BaseVisitor {
1020 constructor(_schema, rawConfig, additionalConfig, defaultScalars = DEFAULT_SCALARS) {
1021 var _a;
1022 super(rawConfig, {
1023 enumPrefix: getConfigValue(rawConfig.enumPrefix, true),
1024 onlyEnums: getConfigValue(rawConfig.onlyEnums, false),
1025 onlyOperationTypes: getConfigValue(rawConfig.onlyOperationTypes, false),
1026 addUnderscoreToArgsType: getConfigValue(rawConfig.addUnderscoreToArgsType, false),
1027 enumValues: parseEnumValues({
1028 schema: _schema,
1029 mapOrStr: rawConfig.enumValues,
1030 ignoreEnumValuesFromSchema: rawConfig.ignoreEnumValuesFromSchema,
1031 }),
1032 declarationKind: normalizeDeclarationKind(rawConfig.declarationKind),
1033 scalars: buildScalarsFromConfig(_schema, rawConfig, defaultScalars),
1034 fieldWrapperValue: getConfigValue(rawConfig.fieldWrapperValue, 'T'),
1035 wrapFieldDefinitions: getConfigValue(rawConfig.wrapFieldDefinitions, false),
1036 entireFieldWrapperValue: getConfigValue(rawConfig.entireFieldWrapperValue, 'T'),
1037 wrapEntireDefinitions: getConfigValue(rawConfig.wrapEntireFieldDefinitions, false),
1038 ignoreEnumValuesFromSchema: getConfigValue(rawConfig.ignoreEnumValuesFromSchema, false),
1039 directiveArgumentAndInputFieldMappings: transformDirectiveArgumentAndInputFieldMappings((_a = rawConfig.directiveArgumentAndInputFieldMappings) !== null && _a !== void 0 ? _a : {}, rawConfig.directiveArgumentAndInputFieldMappingTypeSuffix),
1040 ...additionalConfig,
1041 });
1042 this._schema = _schema;
1043 // Note: Missing directive mappers but not a problem since always overriden by implementors
1044 this._argumentsTransformer = new OperationVariablesToObject(this.scalars, this.convertName);
1045 }
1046 getExportPrefix() {
1047 return 'export ';
1048 }
1049 getFieldWrapperValue() {
1050 if (this.config.fieldWrapperValue) {
1051 return `${this.getExportPrefix()}type FieldWrapper<T> = ${this.config.fieldWrapperValue};`;
1052 }
1053 return '';
1054 }
1055 getEntireFieldWrapperValue() {
1056 if (this.config.entireFieldWrapperValue) {
1057 return `${this.getExportPrefix()}type EntireFieldWrapper<T> = ${this.config.entireFieldWrapperValue};`;
1058 }
1059 return '';
1060 }
1061 getScalarsImports() {
1062 return Object.keys(this.config.scalars)
1063 .map(enumName => {
1064 const mappedValue = this.config.scalars[enumName];
1065 if (mappedValue.isExternal) {
1066 return this._buildTypeImport(mappedValue.import, mappedValue.source, mappedValue.default);
1067 }
1068 return null;
1069 })
1070 .filter(a => a);
1071 }
1072 getDirectiveArgumentAndInputFieldMappingsImports() {
1073 return Object.keys(this.config.directiveArgumentAndInputFieldMappings)
1074 .map(directive => {
1075 const mappedValue = this.config.directiveArgumentAndInputFieldMappings[directive];
1076 if (mappedValue.isExternal) {
1077 return this._buildTypeImport(mappedValue.import, mappedValue.source, mappedValue.default);
1078 }
1079 return null;
1080 })
1081 .filter(a => a);
1082 }
1083 get scalarsDefinition() {
1084 if (this.config.onlyEnums)
1085 return '';
1086 const allScalars = Object.keys(this.config.scalars).map(scalarName => {
1087 const scalarValue = this.config.scalars[scalarName].type;
1088 const scalarType = this._schema.getType(scalarName);
1089 const comment = scalarType && scalarType.astNode && scalarType.description ? transformComment(scalarType.description, 1) : '';
1090 const { scalar } = this._parsedConfig.declarationKind;
1091 return comment + indent(`${scalarName}: ${scalarValue}${this.getPunctuation(scalar)}`);
1092 });
1093 return new DeclarationBlock(this._declarationBlockConfig)
1094 .export()
1095 .asKind(this._parsedConfig.declarationKind.scalar)
1096 .withName('Scalars')
1097 .withComment('All built-in and custom scalars, mapped to their actual values')
1098 .withBlock(allScalars.join('\n')).string;
1099 }
1100 get directiveArgumentAndInputFieldMappingsDefinition() {
1101 const directiveEntries = Object.entries(this.config.directiveArgumentAndInputFieldMappings);
1102 if (directiveEntries.length === 0) {
1103 return '';
1104 }
1105 const allDirectives = [];
1106 for (const [directiveName, parsedMapper] of directiveEntries) {
1107 const directiveType = this._schema.getDirective(directiveName);
1108 const comment = (directiveType === null || directiveType === void 0 ? void 0 : directiveType.astNode) && directiveType.description ? transformComment(directiveType.description, 1) : '';
1109 const { directive } = this._parsedConfig.declarationKind;
1110 allDirectives.push(comment + indent(`${directiveName}: ${parsedMapper.type}${this.getPunctuation(directive)}`));
1111 }
1112 return new DeclarationBlock(this._declarationBlockConfig)
1113 .export()
1114 .asKind(this._parsedConfig.declarationKind.directive)
1115 .withName('DirectiveArgumentAndInputFieldMappings')
1116 .withComment('Type overrides using directives')
1117 .withBlock(allDirectives.join('\n')).string;
1118 }
1119 setDeclarationBlockConfig(config) {
1120 this._declarationBlockConfig = config;
1121 }
1122 setArgumentsTransformer(argumentsTransfomer) {
1123 this._argumentsTransformer = argumentsTransfomer;
1124 }
1125 NonNullType(node) {
1126 const asString = node.type;
1127 return asString;
1128 }
1129 getInputObjectDeclarationBlock(node) {
1130 return new DeclarationBlock(this._declarationBlockConfig)
1131 .export()
1132 .asKind(this._parsedConfig.declarationKind.input)
1133 .withName(this.convertName(node))
1134 .withComment(node.description)
1135 .withBlock(node.fields.join('\n'));
1136 }
1137 InputObjectTypeDefinition(node) {
1138 if (this.config.onlyEnums)
1139 return '';
1140 return this.getInputObjectDeclarationBlock(node).string;
1141 }
1142 InputValueDefinition(node) {
1143 if (this.config.onlyEnums)
1144 return '';
1145 const comment = transformComment(node.description, 1);
1146 const { input } = this._parsedConfig.declarationKind;
1147 let type = node.type;
1148 if (node.directives && this.config.directiveArgumentAndInputFieldMappings) {
1149 type = this._getDirectiveOverrideType(node.directives) || type;
1150 }
1151 return comment + indent(`${node.name}: ${type}${this.getPunctuation(input)}`);
1152 }
1153 Name(node) {
1154 return node.value;
1155 }
1156 FieldDefinition(node) {
1157 if (this.config.onlyEnums)
1158 return '';
1159 const typeString = node.type;
1160 const { type } = this._parsedConfig.declarationKind;
1161 const comment = this.getNodeComment(node);
1162 return comment + indent(`${node.name}: ${typeString}${this.getPunctuation(type)}`);
1163 }
1164 UnionTypeDefinition(node, key, parent) {
1165 if (this.config.onlyOperationTypes || this.config.onlyEnums)
1166 return '';
1167 const originalNode = parent[key];
1168 const possibleTypes = originalNode.types
1169 .map(t => (this.scalars[t.name.value] ? this._getScalar(t.name.value) : this.convertName(t)))
1170 .join(' | ');
1171 return new DeclarationBlock(this._declarationBlockConfig)
1172 .export()
1173 .asKind('type')
1174 .withName(this.convertName(node))
1175 .withComment(node.description)
1176 .withContent(possibleTypes).string;
1177 }
1178 mergeInterfaces(interfaces, hasOtherFields) {
1179 return interfaces.join(' & ') + (interfaces.length && hasOtherFields ? ' & ' : '');
1180 }
1181 appendInterfacesAndFieldsToBlock(block, interfaces, fields) {
1182 block.withContent(this.mergeInterfaces(interfaces, fields.length > 0));
1183 block.withBlock(this.mergeAllFields(fields, interfaces.length > 0));
1184 }
1185 getObjectTypeDeclarationBlock(node, originalNode) {
1186 const optionalTypename = this.config.nonOptionalTypename ? '__typename' : '__typename?';
1187 const { type, interface: interfacesType } = this._parsedConfig.declarationKind;
1188 const allFields = [
1189 ...(this.config.addTypename
1190 ? [
1191 indent(`${this.config.immutableTypes ? 'readonly ' : ''}${optionalTypename}: '${node.name}'${this.getPunctuation(type)}`),
1192 ]
1193 : []),
1194 ...node.fields,
1195 ];
1196 const interfacesNames = originalNode.interfaces ? originalNode.interfaces.map(i => this.convertName(i)) : [];
1197 const declarationBlock = new DeclarationBlock(this._declarationBlockConfig)
1198 .export()
1199 .asKind(type)
1200 .withName(this.convertName(node))
1201 .withComment(node.description);
1202 if (type === 'interface' || type === 'class') {
1203 if (interfacesNames.length > 0) {
1204 const keyword = interfacesType === 'interface' && type === 'class' ? 'implements' : 'extends';
1205 declarationBlock.withContent(`${keyword} ` + interfacesNames.join(', ') + (allFields.length > 0 ? ' ' : ' {}'));
1206 }
1207 declarationBlock.withBlock(this.mergeAllFields(allFields, false));
1208 }
1209 else {
1210 this.appendInterfacesAndFieldsToBlock(declarationBlock, interfacesNames, allFields);
1211 }
1212 return declarationBlock;
1213 }
1214 mergeAllFields(allFields, _hasInterfaces) {
1215 return allFields.join('\n');
1216 }
1217 ObjectTypeDefinition(node, key, parent) {
1218 if (this.config.onlyOperationTypes || this.config.onlyEnums)
1219 return '';
1220 const originalNode = parent[key];
1221 return [this.getObjectTypeDeclarationBlock(node, originalNode).string, this.buildArgumentsBlock(originalNode)]
1222 .filter(f => f)
1223 .join('\n\n');
1224 }
1225 getInterfaceTypeDeclarationBlock(node, _originalNode) {
1226 const declarationBlock = new DeclarationBlock(this._declarationBlockConfig)
1227 .export()
1228 .asKind(this._parsedConfig.declarationKind.interface)
1229 .withName(this.convertName(node))
1230 .withComment(node.description);
1231 return declarationBlock.withBlock(node.fields.join('\n'));
1232 }
1233 InterfaceTypeDefinition(node, key, parent) {
1234 if (this.config.onlyOperationTypes || this.config.onlyEnums)
1235 return '';
1236 const originalNode = parent[key];
1237 return [this.getInterfaceTypeDeclarationBlock(node, originalNode).string, this.buildArgumentsBlock(originalNode)]
1238 .filter(f => f)
1239 .join('\n\n');
1240 }
1241 ScalarTypeDefinition(_node) {
1242 // We empty this because we handle scalars in a different way, see constructor.
1243 return '';
1244 }
1245 _buildTypeImport(identifier, source, asDefault = false) {
1246 const { useTypeImports } = this.config;
1247 if (asDefault) {
1248 if (useTypeImports) {
1249 return `import type { default as ${identifier} } from '${source}';`;
1250 }
1251 return `import ${identifier} from '${source}';`;
1252 }
1253 return `import${useTypeImports ? ' type' : ''} { ${identifier} } from '${source}';`;
1254 }
1255 handleEnumValueMapper(typeIdentifier, importIdentifier, sourceIdentifier, sourceFile) {
1256 const importStatement = this._buildTypeImport(importIdentifier || sourceIdentifier, sourceFile);
1257 if (importIdentifier !== sourceIdentifier || sourceIdentifier !== typeIdentifier) {
1258 return [importStatement, `import ${typeIdentifier} = ${sourceIdentifier};`];
1259 }
1260 return [importStatement];
1261 }
1262 getEnumsImports() {
1263 return Object.keys(this.config.enumValues)
1264 .flatMap(enumName => {
1265 const mappedValue = this.config.enumValues[enumName];
1266 if (mappedValue.sourceFile) {
1267 if (mappedValue.isDefault) {
1268 return [this._buildTypeImport(mappedValue.typeIdentifier, mappedValue.sourceFile, true)];
1269 }
1270 return this.handleEnumValueMapper(mappedValue.typeIdentifier, mappedValue.importIdentifier, mappedValue.sourceIdentifier, mappedValue.sourceFile);
1271 }
1272 return [];
1273 })
1274 .filter(Boolean);
1275 }
1276 EnumTypeDefinition(node) {
1277 const enumName = node.name;
1278 // In case of mapped external enum string
1279 if (this.config.enumValues[enumName] && this.config.enumValues[enumName].sourceFile) {
1280 return null;
1281 }
1282 return new DeclarationBlock(this._declarationBlockConfig)
1283 .export()
1284 .asKind('enum')
1285 .withName(this.convertName(node, { useTypesPrefix: this.config.enumPrefix }))
1286 .withComment(node.description)
1287 .withBlock(this.buildEnumValuesBlock(enumName, node.values)).string;
1288 }
1289 // We are using it in order to transform "description" field
1290 StringValue(node) {
1291 return node.value;
1292 }
1293 makeValidEnumIdentifier(identifier) {
1294 if (/^[0-9]/.exec(identifier)) {
1295 return wrapWithSingleQuotes(identifier, true);
1296 }
1297 return identifier;
1298 }
1299 buildEnumValuesBlock(typeName, values) {
1300 const schemaEnumType = this._schema
1301 ? this._schema.getType(typeName)
1302 : undefined;
1303 return values
1304 .map(enumOption => {
1305 const optionName = this.makeValidEnumIdentifier(this.convertName(enumOption, {
1306 useTypesPrefix: false,
1307 transformUnderscore: true,
1308 }));
1309 const comment = this.getNodeComment(enumOption);
1310 const schemaEnumValue = schemaEnumType && !this.config.ignoreEnumValuesFromSchema
1311 ? schemaEnumType.getValue(enumOption.name).value
1312 : undefined;
1313 let enumValue = typeof schemaEnumValue !== 'undefined' ? schemaEnumValue : enumOption.name;
1314 if (this.config.enumValues[typeName] &&
1315 this.config.enumValues[typeName].mappedValues &&
1316 typeof this.config.enumValues[typeName].mappedValues[enumValue] !== 'undefined') {
1317 enumValue = this.config.enumValues[typeName].mappedValues[enumValue];
1318 }
1319 return (comment +
1320 indent(`${optionName}${this._declarationBlockConfig.enumNameValueSeparator} ${wrapWithSingleQuotes(enumValue, typeof schemaEnumValue !== 'undefined')}`));
1321 })
1322 .join(',\n');
1323 }
1324 DirectiveDefinition(_node) {
1325 return '';
1326 }
1327 getArgumentsObjectDeclarationBlock(node, name, field) {
1328 return new DeclarationBlock(this._declarationBlockConfig)
1329 .export()
1330 .asKind(this._parsedConfig.declarationKind.arguments)
1331 .withName(this.convertName(name))
1332 .withComment(node.description)
1333 .withBlock(this._argumentsTransformer.transform(field.arguments));
1334 }
1335 getArgumentsObjectTypeDefinition(node, name, field) {
1336 if (this.config.onlyEnums)
1337 return '';
1338 return this.getArgumentsObjectDeclarationBlock(node, name, field).string;
1339 }
1340 buildArgumentsBlock(node) {
1341 const fieldsWithArguments = node.fields.filter(field => field.arguments && field.arguments.length > 0) || [];
1342 return fieldsWithArguments
1343 .map(field => {
1344 const name = node.name.value +
1345 (this.config.addUnderscoreToArgsType ? '_' : '') +
1346 this.convertName(field, {
1347 useTypesPrefix: false,
1348 useTypesSuffix: false,
1349 }) +
1350 'Args';
1351 return this.getArgumentsObjectTypeDefinition(node, name, field);
1352 })
1353 .join('\n\n');
1354 }
1355 _getScalar(name) {
1356 return `Scalars['${name}']`;
1357 }
1358 _getDirectiveArgumentNadInputFieldMapping(name) {
1359 return `DirectiveArgumentAndInputFieldMappings['${name}']`;
1360 }
1361 _getDirectiveOverrideType(directives) {
1362 const type = directives
1363 .map(directive => {
1364 const directiveName = directive.name;
1365 if (this.config.directiveArgumentAndInputFieldMappings[directiveName]) {
1366 return this._getDirectiveArgumentNadInputFieldMapping(directiveName);
1367 }
1368 return null;
1369 })
1370 .reverse()
1371 .find(a => !!a);
1372 return type || null;
1373 }
1374 _getTypeForNode(node) {
1375 const typeAsString = node.name;
1376 if (this.scalars[typeAsString]) {
1377 return this._getScalar(typeAsString);
1378 }
1379 else if (this.config.enumValues[typeAsString]) {
1380 return this.config.enumValues[typeAsString].typeIdentifier;
1381 }
1382 const schemaType = this._schema.getType(node.name);
1383 if (schemaType && isEnumType(schemaType)) {
1384 return this.convertName(node, { useTypesPrefix: this.config.enumPrefix });
1385 }
1386 return this.convertName(node);
1387 }
1388 NamedType(node, key, parent, path, ancestors) {
1389 const currentVisitContext = this.getVisitorKindContextFromAncestors(ancestors);
1390 const isVisitingInputType = currentVisitContext.includes(Kind.INPUT_OBJECT_TYPE_DEFINITION);
1391 const typeToUse = this._getTypeForNode(node);
1392 if (!isVisitingInputType && this.config.fieldWrapperValue && this.config.wrapFieldDefinitions) {
1393 return `FieldWrapper<${typeToUse}>`;
1394 }
1395 return typeToUse;
1396 }
1397 ListType(node, key, parent, path, ancestors) {
1398 const asString = node.type;
1399 return this.wrapWithListType(asString);
1400 }
1401 SchemaDefinition() {
1402 return null;
1403 }
1404 getNodeComment(node) {
1405 let commentText = node.description;
1406 const deprecationDirective = node.directives.find((v) => v.name === 'deprecated');
1407 if (deprecationDirective) {
1408 const deprecationReason = this.getDeprecationReason(deprecationDirective);
1409 commentText = `${commentText ? `${commentText}\n` : ''}@deprecated ${deprecationReason}`;
1410 }
1411 const comment = transformComment(commentText, 1);
1412 return comment;
1413 }
1414 getDeprecationReason(directive) {
1415 if (directive.name === 'deprecated') {
1416 const hasArguments = directive.arguments.length > 0;
1417 let reason = 'Field no longer supported';
1418 if (hasArguments) {
1419 reason = directive.arguments[0].value;
1420 }
1421 return reason;
1422 }
1423 }
1424 wrapWithListType(str) {
1425 return `Array<${str}>`;
1426 }
1427}
1428
1429function getRootType(operation, schema) {
1430 switch (operation) {
1431 case 'query':
1432 return schema.getQueryType();
1433 case 'mutation':
1434 return schema.getMutationType();
1435 case 'subscription':
1436 return schema.getSubscriptionType();
1437 }
1438 throw new Error(`Unknown operation type: ${operation}`);
1439}
1440class BaseDocumentsVisitor extends BaseVisitor {
1441 constructor(rawConfig, additionalConfig, _schema, defaultScalars = DEFAULT_SCALARS) {
1442 super(rawConfig, {
1443 exportFragmentSpreadSubTypes: getConfigValue(rawConfig.exportFragmentSpreadSubTypes, false),
1444 enumPrefix: getConfigValue(rawConfig.enumPrefix, true),
1445 preResolveTypes: getConfigValue(rawConfig.preResolveTypes, true),
1446 dedupeOperationSuffix: getConfigValue(rawConfig.dedupeOperationSuffix, false),
1447 omitOperationSuffix: getConfigValue(rawConfig.omitOperationSuffix, false),
1448 skipTypeNameForRoot: getConfigValue(rawConfig.skipTypeNameForRoot, false),
1449 namespacedImportName: getConfigValue(rawConfig.namespacedImportName, null),
1450 experimentalFragmentVariables: getConfigValue(rawConfig.experimentalFragmentVariables, false),
1451 addTypename: !rawConfig.skipTypename,
1452 globalNamespace: !!rawConfig.globalNamespace,
1453 operationResultSuffix: getConfigValue(rawConfig.operationResultSuffix, ''),
1454 scalars: buildScalarsFromConfig(_schema, rawConfig, defaultScalars),
1455 ...(additionalConfig || {}),
1456 });
1457 this._schema = _schema;
1458 this._unnamedCounter = 1;
1459 this._globalDeclarations = new Set();
1460 autoBind(this);
1461 this._variablesTransfomer = new OperationVariablesToObject(this.scalars, this.convertName, this.config.namespacedImportName);
1462 }
1463 getGlobalDeclarations(noExport = false) {
1464 return Array.from(this._globalDeclarations).map(t => (noExport ? t : `export ${t}`));
1465 }
1466 setSelectionSetHandler(handler) {
1467 this._selectionSetToObject = handler;
1468 }
1469 setDeclarationBlockConfig(config) {
1470 this._declarationBlockConfig = config;
1471 }
1472 setVariablesTransformer(variablesTransfomer) {
1473 this._variablesTransfomer = variablesTransfomer;
1474 }
1475 get schema() {
1476 return this._schema;
1477 }
1478 get addTypename() {
1479 return this._parsedConfig.addTypename;
1480 }
1481 handleAnonymousOperation(node) {
1482 const name = node.name && node.name.value;
1483 if (name) {
1484 return this.convertName(name, {
1485 useTypesPrefix: false,
1486 useTypesSuffix: false,
1487 });
1488 }
1489 return this.convertName(this._unnamedCounter++ + '', {
1490 prefix: 'Unnamed_',
1491 suffix: '_',
1492 useTypesPrefix: false,
1493 useTypesSuffix: false,
1494 });
1495 }
1496 FragmentDefinition(node) {
1497 const fragmentRootType = this._schema.getType(node.typeCondition.name.value);
1498 const selectionSet = this._selectionSetToObject.createNext(fragmentRootType, node.selectionSet);
1499 const fragmentSuffix = this.getFragmentSuffix(node);
1500 return [
1501 selectionSet.transformFragmentSelectionSetToTypes(node.name.value, fragmentSuffix, this._declarationBlockConfig),
1502 this.config.experimentalFragmentVariables
1503 ? new DeclarationBlock({
1504 ...this._declarationBlockConfig,
1505 blockTransformer: t => this.applyVariablesWrapper(t),
1506 })
1507 .export()
1508 .asKind('type')
1509 .withName(this.convertName(node.name.value, {
1510 suffix: fragmentSuffix + 'Variables',
1511 }))
1512 .withBlock(this._variablesTransfomer.transform(node.variableDefinitions)).string
1513 : undefined,
1514 ]
1515 .filter(r => r)
1516 .join('\n\n');
1517 }
1518 applyVariablesWrapper(variablesBlock) {
1519 return variablesBlock;
1520 }
1521 OperationDefinition(node) {
1522 const name = this.handleAnonymousOperation(node);
1523 const operationRootType = getRootType(node.operation, this._schema);
1524