diff --git a/.changeset/shaggy-roses-beam.md b/.changeset/shaggy-roses-beam.md new file mode 100644 index 00000000000..46ede494a24 --- /dev/null +++ b/.changeset/shaggy-roses-beam.md @@ -0,0 +1,7 @@ +--- +"@graphql-codegen/testing": minor +"@graphql-codegen/typescript-resolvers": minor +"@graphql-codegen/visitor-plugin-common": minor +--- + +Forward directive arguments params to context type diff --git a/packages/plugins/other/visitor-plugin-common/src/base-resolvers-visitor.ts b/packages/plugins/other/visitor-plugin-common/src/base-resolvers-visitor.ts index 2d20fe39a56..ad1430fbc38 100644 --- a/packages/plugins/other/visitor-plugin-common/src/base-resolvers-visitor.ts +++ b/packages/plugins/other/visitor-plugin-common/src/base-resolvers-visitor.ts @@ -3,6 +3,8 @@ import { getRootTypeNames } from '@graphql-tools/utils'; import autoBind from 'auto-bind'; import { ASTNode, + ObjectValueNode, + ValueNode, DirectiveDefinitionNode, EnumTypeDefinitionNode, FieldDefinitionNode, @@ -51,6 +53,48 @@ import { } from './utils.js'; import { OperationVariablesToObject } from './variables-to-object.js'; +// converts an ObjectValueNode to the JS object it represents +const objectNodeToObject = (objectNode: ObjectValueNode) => { + const { fields } = objectNode; + return fields.reduce((acc, field) => { + // for some reason this does not seem to match the type + const fieldName = field.name as unknown as string; + return { + ...acc, + [fieldName]: valueNodeToValue(field.value), + }; + }, {}); +}; + +// converts an ValueNode to the JS value it represents +const valueNodeToValue = (value: ValueNode): unknown => { + if (value.kind === 'StringValue') { + return value.value; + } + if (value.kind === 'ObjectValue') { + return objectNodeToObject(value); + } + if (value.kind === 'ListValue') { + return value.values.map(valueNodeToValue); + } + if (value.kind === 'NullValue') { + return null; + } + if (value.kind === 'BooleanValue') { + return value.value; + } + if (value.kind === 'IntValue') { + return parseInt(value.value, 10); + } + if (value.kind === 'FloatValue') { + return parseFloat(value.value); + } + if (value.kind === 'EnumValue') { + return value.value; + } + return null; +}; + export interface ParsedResolversConfig extends ParsedConfig { contextType: ParsedMapper; fieldContextTypes: Array; @@ -1490,7 +1534,15 @@ export class BaseResolversVisitor< const name = directive.name as unknown as string; const directiveMap = this._directiveContextTypesMap[name]; if (directiveMap) { - contextType = `${directiveMap.type}<${contextType}>`; + const args = directive.arguments?.reduce((prev, { name, value }) => { + // for some reason this does not seem to match the type + const argumentName = name as unknown as string; + return { + ...prev, + [argumentName]: valueNodeToValue(value), + }; + }, {}); + contextType = `${directiveMap.type}<${contextType}, ${JSON.stringify(args)}>`; } } return contextType; diff --git a/packages/plugins/typescript/resolvers/tests/__snapshots__/ts-resolvers.spec.ts.snap b/packages/plugins/typescript/resolvers/tests/__snapshots__/ts-resolvers.spec.ts.snap index f2ab6d709f2..4fa02ba444b 100644 --- a/packages/plugins/typescript/resolvers/tests/__snapshots__/ts-resolvers.spec.ts.snap +++ b/packages/plugins/typescript/resolvers/tests/__snapshots__/ts-resolvers.spec.ts.snap @@ -24,6 +24,7 @@ export type Scalars = { export type MyType = { __typename?: 'MyType'; foo: Scalars['String']['output']; + bar: Scalars['String']['output']; otherType?: Maybe; withArgs?: Maybe; unionChild?: Maybe; @@ -234,12 +235,15 @@ export type MyDirectiveDirectiveArgs = { export type MyDirectiveDirectiveResolver = DirectiveResolverFn; -export type AuthenticatedDirectiveArgs = { }; +export type AuthenticatedDirectiveArgs = { + role?: Maybe; +}; export type AuthenticatedDirectiveResolver = DirectiveResolverFn; export type MyTypeResolvers = ResolversObject<{ foo?: Resolver; + bar?: Resolver; otherType?: Resolver, ParentType, ContextType>; withArgs?: Resolver, ParentType, ContextType, RequireFields>; unionChild?: Resolver, ParentType, ContextType>; @@ -493,12 +497,15 @@ export type MyDirectiveDirectiveArgs = { export type MyDirectiveDirectiveResolver = DirectiveResolverFn; -export type AuthenticatedDirectiveArgs = { }; +export type AuthenticatedDirectiveArgs = { + role?: Types.Maybe; +}; export type AuthenticatedDirectiveResolver = DirectiveResolverFn; export type MyTypeResolvers = ResolversObject<{ foo?: Resolver; + bar?: Resolver; otherType?: Resolver, ParentType, ContextType>; withArgs?: Resolver, ParentType, ContextType, RequireFields>; unionChild?: Resolver, ParentType, ContextType>; @@ -628,6 +635,7 @@ export type Scalars = { export type MyType = { __typename?: 'MyType'; foo: Scalars['String']['output']; + bar: Scalars['String']['output']; otherType?: Maybe; withArgs?: Maybe; unionChild?: Maybe; @@ -838,12 +846,15 @@ export type MyDirectiveDirectiveArgs = { export type MyDirectiveDirectiveResolver = DirectiveResolverFn; -export type AuthenticatedDirectiveArgs = { }; +export type AuthenticatedDirectiveArgs = { + role?: Maybe; +}; export type AuthenticatedDirectiveResolver = DirectiveResolverFn; export type MyTypeResolvers = ResolversObject<{ foo?: Resolver; + bar?: Resolver; otherType?: Resolver, ParentType, ContextType>; withArgs?: Resolver, ParentType, ContextType, RequireFields>; unionChild?: Resolver, ParentType, ContextType>; diff --git a/packages/plugins/typescript/resolvers/tests/mapping.spec.ts b/packages/plugins/typescript/resolvers/tests/mapping.spec.ts index ec9d5ba7bbf..0e24f33d528 100644 --- a/packages/plugins/typescript/resolvers/tests/mapping.spec.ts +++ b/packages/plugins/typescript/resolvers/tests/mapping.spec.ts @@ -1249,6 +1249,7 @@ describe('ResolversTypes', () => { expect(result.content).toBeSimilarStringTo(` export type MyTypeResolvers = { foo?: Resolver; + bar?: Resolver; otherType?: Resolver, ParentType, ContextType>; withArgs?: Resolver, ParentType, ContextType, RequireFields>; unionChild?: Resolver, ParentType, ContextType>; @@ -1332,6 +1333,7 @@ describe('ResolversTypes', () => { expect(result.content).toBeSimilarStringTo(` export type MyTypeResolvers = { foo?: Resolver; + bar?: Resolver; otherType?: Resolver, ParentType, ContextType>; withArgs?: Resolver, ParentType, ContextType, RequireFields>; unionChild?: Resolver, ParentType, ContextType>; @@ -1413,6 +1415,7 @@ describe('ResolversTypes', () => { expect(result.content).toBeSimilarStringTo(` export type MyTypeResolvers = { foo?: Resolver; + bar?: Resolver; otherType?: Resolver, ParentType, ContextType>; withArgs?: Resolver, ParentType, ContextType, RequireFields>; unionChild?: Resolver, ParentType, ContextType>; @@ -1483,6 +1486,7 @@ describe('ResolversTypes', () => { expect(result.content).toBeSimilarStringTo(` export type MyTypeResolvers = { foo?: Resolver; + bar?: Resolver; otherType?: Resolver, ParentType, ContextType>; withArgs?: Resolver, ParentType, ContextType, RequireFields>; unionChild?: Resolver, ParentType, ContextType>; @@ -1553,6 +1557,7 @@ describe('ResolversTypes', () => { expect(result.content).toBeSimilarStringTo(` export type MyTypeResolvers = { foo?: Resolver; + bar?: Resolver; otherType?: Resolver, ParentType, ContextType>; withArgs?: Resolver, ParentType, ContextType, RequireFields>; unionChild?: Resolver, ParentType, ContextType>; diff --git a/packages/plugins/typescript/resolvers/tests/ts-resolvers.spec.ts b/packages/plugins/typescript/resolvers/tests/ts-resolvers.spec.ts index c557bad7b97..c9c9bef8c4d 100644 --- a/packages/plugins/typescript/resolvers/tests/ts-resolvers.spec.ts +++ b/packages/plugins/typescript/resolvers/tests/ts-resolvers.spec.ts @@ -183,6 +183,7 @@ export type ResolverAuthenticated = { foo?: ResolverAuthenticated; + bar?: ResolverAuthenticated; otherType?: Resolver, ParentType, ContextType>; withArgs?: Resolver, ParentType, ContextType, RequireFields>; unionChild?: Resolver, ParentType, ContextType>; @@ -485,6 +486,7 @@ export type ResolverAuthenticated = { foo?: ResolverAuthenticated; +bar?: ResolverAuthenticated; otherType?: Resolver, ParentType, ContextType>; withArgs?: Resolver, ParentType, ContextType, RequireFields>; unionChild?: Resolver, ParentType, ContextType>; @@ -916,6 +918,7 @@ __isTypeOf?: IsTypeOfResolverFn; expect(result.content).toBeSimilarStringTo(` export type MyTypeResolvers = { foo?: Resolver; + bar?: Resolver; otherType?: Resolver, ParentType, ContextType>; withArgs?: Resolver, ParentType, ContextType, RequireFields>; unionChild?: Resolver, ParentType, ContextType>; @@ -991,6 +994,7 @@ __isTypeOf?: IsTypeOfResolverFn; expect(result.content).toBeSimilarStringTo(` export type MyTypeResolvers = { foo: Resolver; + bar: Resolver; otherType: Resolver, ParentType, ContextType>; withArgs: Resolver, ParentType, ContextType, RequireFields>; unionChild: Resolver, ParentType, ContextType>; @@ -1064,6 +1068,7 @@ __isTypeOf?: IsTypeOfResolverFn; expect(result.content).toBeSimilarStringTo(` export type MyTypeResolvers = { foo?: Resolver; + bar?: Resolver; otherType?: Resolver, ParentType, ContextType>; withArgs?: Resolver, ParentType, ContextType, RequireFields>; unionChild?: Resolver, ParentType, ContextType>; @@ -1155,6 +1160,7 @@ __isTypeOf?: IsTypeOfResolverFn; expect(result.content).toBeSimilarStringTo(` export type MyTypeResolvers = { foo?: Resolver; + bar?: Resolver; otherType?: Resolver, ParentType, ContextType>; withArgs?: Resolver, ParentType, ContextType, RequireFields>; unionChild?: Resolver, ParentType, ContextType>; @@ -1230,6 +1236,7 @@ __isTypeOf?: IsTypeOfResolverFn; expect(result.content).toBeSimilarStringTo(` export type MyTypeResolvers = { foo?: Resolver; + bar?: Resolver; otherType?: Resolver, ParentType, ContextType>; withArgs?: Resolver, ParentType, ContextType, RequireFields>; unionChild?: Resolver, ParentType, ContextType>; @@ -1304,6 +1311,7 @@ __isTypeOf?: IsTypeOfResolverFn; expect(result.content).toBeSimilarStringTo(` export type MyTypeResolvers = { foo?: Resolver; + bar?: Resolver; otherType?: Resolver, ParentType, ContextType>; withArgs?: Resolver, ParentType, ContextType, RequireFields>; unionChild?: Resolver, ParentType, ContextType>; @@ -1379,6 +1387,7 @@ __isTypeOf?: IsTypeOfResolverFn; expect(result.content).toBeSimilarStringTo(` export type MyTypeResolvers = { foo?: Resolver; + bar?: Resolver; otherType?: Resolver, ParentType, ContextType>; withArgs?: Resolver, ParentType, ContextType, RequireFields>; unionChild?: Resolver, ParentType, ContextType>; @@ -1440,6 +1449,7 @@ __isTypeOf?: IsTypeOfResolverFn; expect(result.content).toBeSimilarStringTo(` export type MyTypeResolvers = { foo?: Resolver; + bar?: Resolver; otherType?: Resolver, ParentType, SpecialContextType>; withArgs?: Resolver, ParentType, ContextType, RequireFields>; unionChild?: Resolver, ParentType, ContextType>; @@ -1468,7 +1478,8 @@ __isTypeOf?: IsTypeOfResolverFn; expect(result.content).toBeSimilarStringTo(` export type MyTypeResolvers = { - foo?: Resolver>; + foo?: Resolver>; + bar?: Resolver>; otherType?: Resolver, ParentType, ContextType>; withArgs?: Resolver, ParentType, ContextType, RequireFields>; unionChild?: Resolver, ParentType, ContextType>; @@ -1492,7 +1503,8 @@ __isTypeOf?: IsTypeOfResolverFn; expect(result.content).toBeSimilarStringTo(` export type MyTypeResolvers = { - foo?: Resolver>; + foo?: Resolver>; + bar?: Resolver>; otherType?: Resolver, ParentType, ContextType>; withArgs?: Resolver, ParentType, ContextType, RequireFields>; unionChild?: Resolver, ParentType, ContextType>; @@ -1516,7 +1528,8 @@ __isTypeOf?: IsTypeOfResolverFn; expect(result.content).toBeSimilarStringTo(` export type MyTypeResolvers = { - foo?: Resolver>; + foo?: Resolver>; + bar?: Resolver>; otherType?: Resolver, ParentType, ContextType>; withArgs?: Resolver, ParentType, ContextType, RequireFields>; unionChild?: Resolver, ParentType, ContextType>; diff --git a/packages/utils/graphql-codegen-testing/src/resolvers-common.ts b/packages/utils/graphql-codegen-testing/src/resolvers-common.ts index ab2f0c9fdf1..7d550031e9f 100644 --- a/packages/utils/graphql-codegen-testing/src/resolvers-common.ts +++ b/packages/utils/graphql-codegen-testing/src/resolvers-common.ts @@ -6,6 +6,7 @@ import { buildSchema } from 'graphql'; export const resolversTestingSchema = buildSchema(/* GraphQL */ ` type MyType { foo: String! @authenticated + bar: String! @authenticated(role: "admin") otherType: MyOtherType withArgs(arg: String, arg2: String!): String unionChild: ChildUnion @@ -71,7 +72,7 @@ export const resolversTestingSchema = buildSchema(/* GraphQL */ ` scalar MyScalar directive @myDirective(arg: Int!, arg2: String!, arg3: Boolean!) on FIELD - directive @authenticated on FIELD_DEFINITION + directive @authenticated(role: String) on FIELD_DEFINITION `); export const resolversTestingValidate = async (