UNPKG

13 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', { value: true });
4
5function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
6
7const utils = require('@graphql-tools/utils');
8const visitorPluginCommon = require('@graphql-codegen/visitor-plugin-common');
9const pluginHelpers = require('@graphql-codegen/plugin-helpers');
10const graphql = require('graphql');
11const autoBind = _interopDefault(require('auto-bind'));
12const typescript = require('@graphql-codegen/typescript');
13
14const ENUM_RESOLVERS_SIGNATURE = 'export type EnumResolverSignature<T, AllowedValues = any> = { [key in keyof T]?: AllowedValues };';
15class TypeScriptResolversVisitor extends visitorPluginCommon.BaseResolversVisitor {
16 constructor(pluginConfig, schema) {
17 super(pluginConfig, {
18 avoidOptionals: visitorPluginCommon.getConfigValue(pluginConfig.avoidOptionals, false),
19 useIndexSignature: visitorPluginCommon.getConfigValue(pluginConfig.useIndexSignature, false),
20 wrapFieldDefinitions: visitorPluginCommon.getConfigValue(pluginConfig.wrapFieldDefinitions, false),
21 allowParentTypeOverride: visitorPluginCommon.getConfigValue(pluginConfig.allowParentTypeOverride, false),
22 optionalInfoArgument: visitorPluginCommon.getConfigValue(pluginConfig.optionalInfoArgument, false),
23 }, schema);
24 autoBind(this);
25 this.setVariablesTransformer(new typescript.TypeScriptOperationVariablesToObject(this.scalars, this.convertName, this.config.avoidOptionals, this.config.immutableTypes, this.config.namespacedImportName, [], this.config.enumPrefix, this.config.enumValues));
26 if (this.config.useIndexSignature) {
27 this._declarationBlockConfig = {
28 blockTransformer(block) {
29 return `ResolversObject<${block}>`;
30 },
31 };
32 }
33 }
34 transformParentGenericType(parentType) {
35 if (this.config.allowParentTypeOverride) {
36 return `ParentType = ${parentType}`;
37 }
38 return `ParentType extends ${parentType} = ${parentType}`;
39 }
40 formatRootResolver(schemaTypeName, resolverType, declarationKind) {
41 return `${schemaTypeName}${this.config.avoidOptionals ? '' : '?'}: ${resolverType}${this.getPunctuation(declarationKind)}`;
42 }
43 clearOptional(str) {
44 if (str.startsWith('Maybe')) {
45 return str.replace(/Maybe<(.*?)>$/, '$1');
46 }
47 return str;
48 }
49 ListType(node) {
50 return `Maybe<${super.ListType(node)}>`;
51 }
52 wrapWithListType(str) {
53 return `${this.config.immutableTypes ? 'ReadonlyArray' : 'Array'}<${str}>`;
54 }
55 getParentTypeForSignature(node) {
56 if (this._federation.isResolveReferenceField(node) && this.config.wrapFieldDefinitions) {
57 return 'UnwrappedObject<ParentType>';
58 }
59 return 'ParentType';
60 }
61 NamedType(node) {
62 return `Maybe<${super.NamedType(node)}>`;
63 }
64 NonNullType(node) {
65 const baseValue = super.NonNullType(node);
66 return this.clearOptional(baseValue);
67 }
68 getPunctuation(declarationKind) {
69 return ';';
70 }
71 buildEnumResolverContentBlock(node, mappedEnumType) {
72 const valuesMap = `{ ${(node.values || [])
73 .map(v => `${v.name}${this.config.avoidOptionals ? '' : '?'}: any`)
74 .join(', ')} }`;
75 this._globalDeclarations.add(ENUM_RESOLVERS_SIGNATURE);
76 return `EnumResolverSignature<${valuesMap}, ${mappedEnumType}>`;
77 }
78 buildEnumResolversExplicitMappedValues(node, valuesMapping) {
79 return `{ ${(node.values || [])
80 .map(v => {
81 const valueName = v.name;
82 const mappedValue = valuesMapping[valueName];
83 return `${valueName}: ${typeof mappedValue === 'number' ? mappedValue : `'${mappedValue}'`}`;
84 })
85 .join(', ')} }`;
86 }
87}
88
89const plugin = (schema, documents, config) => {
90 const imports = [];
91 if (!config.customResolveInfo) {
92 imports.push('GraphQLResolveInfo');
93 }
94 const showUnusedMappers = typeof config.showUnusedMappers === 'boolean' ? config.showUnusedMappers : true;
95 const noSchemaStitching = typeof config.noSchemaStitching === 'boolean' ? config.noSchemaStitching : false;
96 if (config.noSchemaStitching === false) {
97 // eslint-disable-next-line no-console
98 console.warn(`The default behavior of 'noSchemaStitching' will be reversed in the next major release. Support for Schema Stitching will be disabled by default.`);
99 }
100 const indexSignature = config.useIndexSignature
101 ? [
102 'export type WithIndex<TObject> = TObject & Record<string, any>;',
103 'export type ResolversObject<TObject> = WithIndex<TObject>;',
104 ].join('\n')
105 : '';
106 const transformedSchema = config.federation ? pluginHelpers.addFederationReferencesToSchema(schema) : schema;
107 const visitor = new TypeScriptResolversVisitor(config, transformedSchema);
108 const namespacedImportPrefix = visitor.config.namespacedImportName ? `${visitor.config.namespacedImportName}.` : '';
109 const printedSchema = config.federation
110 ? utils.printSchemaWithDirectives(transformedSchema)
111 : graphql.printSchema(transformedSchema);
112 const astNode = graphql.parse(printedSchema);
113 // runs visitor
114 const visitorResult = graphql.visit(astNode, { leave: visitor });
115 const optionalSignForInfoArg = visitor.config.optionalInfoArgument ? '?' : '';
116 const prepend = [];
117 const defsToInclude = [];
118 const legacyStitchingResolverType = `
119export type LegacyStitchingResolver<TResult, TParent, TContext, TArgs> = {
120 fragment: string;
121 resolve: ResolverFn<TResult, TParent, TContext, TArgs>;
122};`;
123 const newStitchingResolverType = `
124export type NewStitchingResolver<TResult, TParent, TContext, TArgs> = {
125 selectionSet: string;
126 resolve: ResolverFn<TResult, TParent, TContext, TArgs>;
127};`;
128 const stitchingResolverType = `export type StitchingResolver<TResult, TParent, TContext, TArgs> = LegacyStitchingResolver<TResult, TParent, TContext, TArgs> | NewStitchingResolver<TResult, TParent, TContext, TArgs>;`;
129 const resolverType = `export type Resolver<TResult, TParent = {}, TContext = {}, TArgs = {}> =`;
130 const resolverFnUsage = `ResolverFn<TResult, TParent, TContext, TArgs>`;
131 const stitchingResolverUsage = `StitchingResolver<TResult, TParent, TContext, TArgs>`;
132 if (visitor.hasFederation()) {
133 if (visitor.config.wrapFieldDefinitions) {
134 defsToInclude.push(`export type UnwrappedObject<T> = {
135 [P in keyof T]: T[P] extends infer R | Promise<infer R> | (() => infer R2 | Promise<infer R2>)
136 ? R & R2 : T[P]
137 };`);
138 }
139 defsToInclude.push(`export type ReferenceResolver<TResult, TReference, TContext> = (
140 reference: TReference,
141 context: TContext,
142 info${optionalSignForInfoArg}: GraphQLResolveInfo
143 ) => Promise<TResult> | TResult;`);
144 defsToInclude.push(`
145 type ScalarCheck<T, S> = S extends true ? T : NullableCheck<T, S>;
146 type NullableCheck<T, S> = Maybe<T> extends T ? Maybe<ListCheck<NonNullable<T>, S>> : ListCheck<T, S>;
147 type ListCheck<T, S> = T extends (infer U)[] ? NullableCheck<U, S>[] : GraphQLRecursivePick<T, S>;
148 export type GraphQLRecursivePick<T, S> = { [K in keyof T & keyof S]: ScalarCheck<T[K], S[K]> };
149 `);
150 }
151 if (noSchemaStitching) {
152 // Resolver = ResolverFn;
153 defsToInclude.push(`${resolverType} ${resolverFnUsage};`);
154 }
155 else {
156 // StitchingResolver
157 // Resolver =
158 // | ResolverFn
159 // | StitchingResolver;
160 defsToInclude.push([
161 legacyStitchingResolverType,
162 newStitchingResolverType,
163 stitchingResolverType,
164 resolverType,
165 ` | ${resolverFnUsage}`,
166 ` | ${stitchingResolverUsage};`,
167 ].join('\n'));
168 }
169 if (config.customResolverFn) {
170 const parsedMapper = visitorPluginCommon.parseMapper(config.customResolverFn);
171 if (parsedMapper.isExternal) {
172 if (parsedMapper.default) {
173 prepend.push(`import ResolverFn from '${parsedMapper.source}';`);
174 }
175 else {
176 prepend.push(`import { ${parsedMapper.import} ${parsedMapper.import !== 'ResolverFn' ? 'as ResolverFn ' : ''}} from '${parsedMapper.source}';`);
177 }
178 prepend.push(`export { ResolverFn };`);
179 }
180 else {
181 prepend.push(`export type ResolverFn<TResult, TParent, TContext, TArgs> = ${parsedMapper.type}`);
182 }
183 }
184 else {
185 const defaultResolverFn = `
186export type ResolverFn<TResult, TParent, TContext, TArgs> = (
187 parent: TParent,
188 args: TArgs,
189 context: TContext,
190 info${optionalSignForInfoArg}: GraphQLResolveInfo
191) => Promise<TResult> | TResult;`;
192 defsToInclude.push(defaultResolverFn);
193 }
194 const header = `${indexSignature}
195
196${visitor.getResolverTypeWrapperSignature()}
197
198${defsToInclude.join('\n')}
199
200export type SubscriptionSubscribeFn<TResult, TParent, TContext, TArgs> = (
201 parent: TParent,
202 args: TArgs,
203 context: TContext,
204 info${optionalSignForInfoArg}: GraphQLResolveInfo
205) => AsyncIterator<TResult> | Promise<AsyncIterator<TResult>>;
206
207export type SubscriptionResolveFn<TResult, TParent, TContext, TArgs> = (
208 parent: TParent,
209 args: TArgs,
210 context: TContext,
211 info${optionalSignForInfoArg}: GraphQLResolveInfo
212) => TResult | Promise<TResult>;
213
214export interface SubscriptionSubscriberObject<TResult, TKey extends string, TParent, TContext, TArgs> {
215 subscribe: SubscriptionSubscribeFn<{ [key in TKey]: TResult }, TParent, TContext, TArgs>;
216 resolve?: SubscriptionResolveFn<TResult, { [key in TKey]: TResult }, TContext, TArgs>;
217}
218
219export interface SubscriptionResolverObject<TResult, TParent, TContext, TArgs> {
220 subscribe: SubscriptionSubscribeFn<any, TParent, TContext, TArgs>;
221 resolve: SubscriptionResolveFn<TResult, any, TContext, TArgs>;
222}
223
224export type SubscriptionObject<TResult, TKey extends string, TParent, TContext, TArgs> =
225 | SubscriptionSubscriberObject<TResult, TKey, TParent, TContext, TArgs>
226 | SubscriptionResolverObject<TResult, TParent, TContext, TArgs>;
227
228export type SubscriptionResolver<TResult, TKey extends string, TParent = {}, TContext = {}, TArgs = {}> =
229 | ((...args: any[]) => SubscriptionObject<TResult, TKey, TParent, TContext, TArgs>)
230 | SubscriptionObject<TResult, TKey, TParent, TContext, TArgs>;
231
232export type TypeResolveFn<TTypes, TParent = {}, TContext = {}> = (
233 parent: TParent,
234 context: TContext,
235 info${optionalSignForInfoArg}: GraphQLResolveInfo
236) => ${namespacedImportPrefix}Maybe<TTypes> | Promise<${namespacedImportPrefix}Maybe<TTypes>>;
237
238export type IsTypeOfResolverFn<T = {}> = (obj: T, info${optionalSignForInfoArg}: GraphQLResolveInfo) => boolean | Promise<boolean>;
239
240export type NextResolverFn<T> = () => Promise<T>;
241
242export type DirectiveResolverFn<TResult = {}, TParent = {}, TContext = {}, TArgs = {}> = (
243 next: NextResolverFn<TResult>,
244 parent: TParent,
245 args: TArgs,
246 context: TContext,
247 info${optionalSignForInfoArg}: GraphQLResolveInfo
248) => TResult | Promise<TResult>;
249`;
250 const resolversTypeMapping = visitor.buildResolversTypes();
251 const resolversParentTypeMapping = visitor.buildResolversParentTypes();
252 const { getRootResolver, getAllDirectiveResolvers, mappersImports, unusedMappers, hasScalars } = visitor;
253 if (hasScalars()) {
254 imports.push('GraphQLScalarType', 'GraphQLScalarTypeConfig');
255 }
256 if (showUnusedMappers && unusedMappers.length) {
257 // eslint-disable-next-line no-console
258 console.warn(`Unused mappers: ${unusedMappers.join(',')}`);
259 }
260 if (imports.length) {
261 prepend.push(`import { ${imports.join(', ')} } from 'graphql';`);
262 }
263 if (config.customResolveInfo) {
264 const parsedMapper = visitorPluginCommon.parseMapper(config.customResolveInfo);
265 if (parsedMapper.isExternal) {
266 if (parsedMapper.default) {
267 prepend.push(`import GraphQLResolveInfo from '${parsedMapper.source}'`);
268 }
269 prepend.push(`import { ${parsedMapper.import} ${parsedMapper.import !== 'GraphQLResolveInfo' ? 'as GraphQLResolveInfo' : ''} } from '${parsedMapper.source}';`);
270 }
271 else {
272 prepend.push(`type GraphQLResolveInfo = ${parsedMapper.type}`);
273 }
274 }
275 prepend.push(...mappersImports, ...visitor.globalDeclarations);
276 return {
277 prepend,
278 content: [
279 header,
280 resolversTypeMapping,
281 resolversParentTypeMapping,
282 ...visitorResult.definitions.filter(d => typeof d === 'string'),
283 getRootResolver(),
284 getAllDirectiveResolvers(),
285 ].join('\n'),
286 };
287};
288
289exports.TypeScriptResolversVisitor = TypeScriptResolversVisitor;
290exports.plugin = plugin;
291//# sourceMappingURL=index.cjs.js.map