Skip to content

Commit dfc5310

Browse files
authored
[typescript-resolvers] Add meta field to typescript-resolvers plugin's output (#9961)
* Make typescript-resolvers generate meta of generated typenames * Add changeset for @graphql-codegen/plugin-helpers * Add changeset for typescript-resolvers meta field * Use minor instead of patch for typescript-resolvers
1 parent b49457b commit dfc5310

File tree

6 files changed

+157
-16
lines changed

6 files changed

+157
-16
lines changed

.changeset/curvy-lobsters-kneel.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@graphql-codegen/plugin-helpers': patch
3+
---
4+
5+
Update plugin output type to allow option `meta` field

.changeset/new-radios-flash.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@graphql-codegen/visitor-plugin-common': minor
3+
'@graphql-codegen/typescript-resolvers': minor
4+
---
5+
6+
Update typescript-resolvers to report generated resolver types in the run to meta field in the output

packages/plugins/other/visitor-plugin-common/src/base-resolvers-visitor.ts

+33-9
Original file line numberDiff line numberDiff line change
@@ -634,7 +634,7 @@ export class BaseResolversVisitor<
634634
> extends BaseVisitor<TRawConfig, TPluginConfig> {
635635
protected _parsedConfig: TPluginConfig;
636636
protected _declarationBlockConfig: DeclarationBlockConfig = {};
637-
protected _collectedResolvers: { [key: string]: string } = {};
637+
protected _collectedResolvers: { [key: string]: { typename: string; baseGeneratedTypename?: string } } = {};
638638
protected _collectedDirectiveResolvers: { [key: string]: string } = {};
639639
protected _variablesTransformer: OperationVariablesToObject;
640640
protected _usedMappers: { [key: string]: boolean } = {};
@@ -1264,12 +1264,13 @@ export class BaseResolversVisitor<
12641264
return this._hasFederation;
12651265
}
12661266

1267-
public getRootResolver(): string {
1267+
public getRootResolver(): { content: string; generatedResolverTypes: Record<string, { name: string }> } {
12681268
const name = this.convertName(this.config.allResolversTypeName);
12691269
const declarationKind = 'type';
12701270
const contextType = `<ContextType = ${this.config.contextType.type}>`;
12711271

1272-
return [
1272+
const generatedResolverTypes: Record<string, { name: string }> = {};
1273+
const content = [
12731274
new DeclarationBlock(this._declarationBlockConfig)
12741275
.export()
12751276
.asKind(declarationKind)
@@ -1279,11 +1280,20 @@ export class BaseResolversVisitor<
12791280
.map(schemaTypeName => {
12801281
const resolverType = this._collectedResolvers[schemaTypeName];
12811282

1282-
return indent(this.formatRootResolver(schemaTypeName, resolverType, declarationKind));
1283+
if (resolverType.baseGeneratedTypename) {
1284+
generatedResolverTypes[schemaTypeName] = { name: resolverType.baseGeneratedTypename };
1285+
}
1286+
1287+
return indent(this.formatRootResolver(schemaTypeName, resolverType.typename, declarationKind));
12831288
})
12841289
.join('\n')
12851290
).string,
12861291
].join('\n');
1292+
1293+
return {
1294+
content,
1295+
generatedResolverTypes,
1296+
};
12871297
}
12881298

12891299
protected formatRootResolver(schemaTypeName: string, resolverType: string, declarationKind: DeclarationKind): string {
@@ -1536,7 +1546,10 @@ export class BaseResolversVisitor<
15361546
.withName(name, `<ContextType = ${this.config.contextType.type}, ${this.transformParentGenericType(parentType)}>`)
15371547
.withBlock(fieldsContent.join('\n'));
15381548

1539-
this._collectedResolvers[node.name as any] = name + '<ContextType>';
1549+
this._collectedResolvers[node.name as any] = {
1550+
typename: name + '<ContextType>',
1551+
baseGeneratedTypename: name,
1552+
};
15401553

15411554
return block.string;
15421555
}
@@ -1552,7 +1565,10 @@ export class BaseResolversVisitor<
15521565
.map(f => `'${f}'`)
15531566
.join(' | ');
15541567

1555-
this._collectedResolvers[node.name as any] = name + '<ContextType>';
1568+
this._collectedResolvers[node.name as any] = {
1569+
typename: name + '<ContextType>',
1570+
baseGeneratedTypename: name,
1571+
};
15561572
const parentType = this.getParentTypeToUse(node.name as any as string);
15571573

15581574
return new DeclarationBlock(this._declarationBlockConfig)
@@ -1577,7 +1593,9 @@ export class BaseResolversVisitor<
15771593
}
15781594

15791595
this._hasScalars = true;
1580-
this._collectedResolvers[node.name as any] = 'GraphQLScalarType';
1596+
this._collectedResolvers[node.name as any] = {
1597+
typename: 'GraphQLScalarType',
1598+
};
15811599

15821600
return new DeclarationBlock({
15831601
...this._declarationBlockConfig,
@@ -1667,7 +1685,10 @@ export class BaseResolversVisitor<
16671685
}
16681686

16691687
const name = this.convertName(node, { suffix: this.config.resolverTypeSuffix });
1670-
this._collectedResolvers[rawTypeName] = name;
1688+
this._collectedResolvers[rawTypeName] = {
1689+
typename: name,
1690+
baseGeneratedTypename: name,
1691+
};
16711692
const hasExplicitValues = this.config.enumValues[rawTypeName]?.mappedValues;
16721693

16731694
return new DeclarationBlock(this._declarationBlockConfig)
@@ -1689,7 +1710,10 @@ export class BaseResolversVisitor<
16891710
const allTypesMap = this._schema.getTypeMap();
16901711
const implementingTypes: string[] = [];
16911712

1692-
this._collectedResolvers[node.name as any] = name + '<ContextType>';
1713+
this._collectedResolvers[node.name as any] = {
1714+
typename: name + '<ContextType>',
1715+
baseGeneratedTypename: name,
1716+
};
16931717

16941718
for (const graphqlType of Object.values(allTypesMap)) {
16951719
if (graphqlType instanceof GraphQLObjectType) {

packages/plugins/typescript/resolvers/src/index.ts

+10-6
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,10 @@ import { TypeScriptResolversVisitor } from './visitor.js';
1212

1313
const capitalize = (s: string): string => s.charAt(0).toUpperCase() + s.slice(1);
1414

15-
export const plugin: PluginFunction<TypeScriptResolversPluginConfig, Types.ComplexPluginOutput> = (
16-
schema: GraphQLSchema,
17-
documents: Types.DocumentFile[],
18-
config: TypeScriptResolversPluginConfig
19-
) => {
15+
export const plugin: PluginFunction<
16+
TypeScriptResolversPluginConfig,
17+
Types.ComplexPluginOutput<{ generatedResolverTypes: Record<string, { name: string }> }>
18+
> = (schema: GraphQLSchema, documents: Types.DocumentFile[], config: TypeScriptResolversPluginConfig) => {
2019
const imports = [];
2120
if (!config.customResolveInfo) {
2221
imports.push('GraphQLResolveInfo');
@@ -280,6 +279,8 @@ export type DirectiveResolverFn<TResult = {}, TParent = {}, TContext = {}, TArgs
280279

281280
prepend.push(...mappersImports, ...visitor.globalDeclarations);
282281

282+
const rootResolver = getRootResolver();
283+
283284
return {
284285
prepend,
285286
content: [
@@ -289,9 +290,12 @@ export type DirectiveResolverFn<TResult = {}, TParent = {}, TContext = {}, TArgs
289290
resolversTypeMapping,
290291
resolversParentTypeMapping,
291292
...visitorResult.definitions.filter(d => typeof d === 'string'),
292-
getRootResolver(),
293+
rootResolver.content,
293294
getAllDirectiveResolvers(),
294295
].join('\n'),
296+
meta: {
297+
generatedResolverTypes: rootResolver.generatedResolverTypes,
298+
},
295299
};
296300
};
297301

packages/plugins/typescript/resolvers/tests/ts-resolvers.spec.ts

+97
Original file line numberDiff line numberDiff line change
@@ -3039,4 +3039,101 @@ export type ResolverFn<TResult, TParent, TContext, TArgs> = (
30393039
};
30403040
`);
30413041
});
3042+
3043+
it('generates meta correctly', async () => {
3044+
const result = await plugin(
3045+
buildSchema(/* GraphQL */ `
3046+
type Query {
3047+
user(id: ID!): User
3048+
post(id: ID!): Post
3049+
}
3050+
3051+
type Mutation {
3052+
createUser(name: String!): CreateUserPayload!
3053+
}
3054+
3055+
interface Node {
3056+
id: ID!
3057+
}
3058+
type Post implements Node {
3059+
id: ID!
3060+
author: User
3061+
}
3062+
type User implements Node {
3063+
id: ID!
3064+
name: String
3065+
}
3066+
3067+
type CreateUserOk {
3068+
user: User!
3069+
}
3070+
3071+
type CreateUserError {
3072+
error: ErrorType!
3073+
}
3074+
3075+
union CreateUserPayload = CreateUserOk | CreateUserError
3076+
3077+
enum ErrorType {
3078+
FORBIDDEN_ERROR
3079+
INTERNAL_ERROR
3080+
}
3081+
`),
3082+
[],
3083+
{
3084+
namingConvention: 'change-case-all#snakeCase',
3085+
enumValues: {
3086+
ErrorType: {
3087+
FORBIDDEN_ERROR: '403',
3088+
INTERNAL_ERROR: '500',
3089+
},
3090+
},
3091+
},
3092+
{ outputFile: '' }
3093+
);
3094+
3095+
expect(result.content).toContain(`export type create_user_error_resolvers`);
3096+
expect(result.content).toContain(`export type create_user_ok_resolvers`);
3097+
expect(result.content).toContain(`export type create_user_payload_resolvers`);
3098+
expect(result.content).toContain(`export type error_type_resolvers`);
3099+
expect(result.content).toContain(`export type mutation_resolvers`);
3100+
expect(result.content).toContain(`export type node_resolvers`);
3101+
expect(result.content).toContain(`export type post_resolvers`);
3102+
expect(result.content).toContain(`export type query_resolvers`);
3103+
expect(result.content).toContain(`export type user_resolvers`);
3104+
3105+
expect(result.meta).toMatchInlineSnapshot(`
3106+
Object {
3107+
"generatedResolverTypes": Object {
3108+
"CreateUserError": Object {
3109+
"name": "create_user_error_resolvers",
3110+
},
3111+
"CreateUserOk": Object {
3112+
"name": "create_user_ok_resolvers",
3113+
},
3114+
"CreateUserPayload": Object {
3115+
"name": "create_user_payload_resolvers",
3116+
},
3117+
"ErrorType": Object {
3118+
"name": "error_type_resolvers",
3119+
},
3120+
"Mutation": Object {
3121+
"name": "mutation_resolvers",
3122+
},
3123+
"Node": Object {
3124+
"name": "node_resolvers",
3125+
},
3126+
"Post": Object {
3127+
"name": "post_resolvers",
3128+
},
3129+
"Query": Object {
3130+
"name": "query_resolvers",
3131+
},
3132+
"User": Object {
3133+
"name": "user_resolvers",
3134+
},
3135+
},
3136+
}
3137+
`);
3138+
});
30423139
});

packages/utils/plugins-helpers/src/types.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -549,7 +549,12 @@ export namespace Types {
549549
noSilentErrors?: boolean;
550550
}
551551

552-
export type ComplexPluginOutput = { content: string; prepend?: string[]; append?: string[] };
552+
export type ComplexPluginOutput<M = Record<string, unknown>> = {
553+
content: string;
554+
prepend?: string[];
555+
append?: string[];
556+
meta?: M;
557+
};
553558
export type PluginOutput = string | ComplexPluginOutput;
554559
export type HookFunction = (...args: any[]) => void | Promise<void>;
555560
export type HookAlterFunction = (...args: any[]) => void | string | Promise<void | string>;

0 commit comments

Comments
 (0)