@@ -26,6 +26,10 @@ import {
2626 transformComment ,
2727} from '@graphql-codegen/visitor-plugin-common' ;
2828import { KotlinResolversPluginRawConfig } from './config.js' ;
29+ import {
30+ VALIDATION_DIRECTIVES ,
31+ parseDirectiveArgs ,
32+ } from './directive-mapping.js' ;
2933
3034export const KOTLIN_SCALARS = {
3135 ID : 'Any' ,
@@ -41,6 +45,7 @@ export interface KotlinResolverParsedConfig extends ParsedConfig {
4145 enumValues : EnumValuesMap ;
4246 withTypes : boolean ;
4347 omitJvmStatic : boolean ;
48+ validationAnnotations ?: boolean ;
4449}
4550
4651export interface FieldDefinitionReturnType {
@@ -64,6 +69,7 @@ export class KotlinResolversVisitor extends BaseVisitor<
6469 package : rawConfig . package || defaultPackageName ,
6570 scalars : buildScalarsFromConfig ( _schema , rawConfig , KOTLIN_SCALARS ) ,
6671 omitJvmStatic : rawConfig . omitJvmStatic || false ,
72+ validationAnnotations : rawConfig . validationAnnotations || false ,
6773 } ) ;
6874 }
6975
@@ -177,6 +183,110 @@ ${enumValues}
177183 return result ;
178184 }
179185
186+ /**
187+ * Extract validation annotations from field directives
188+ */
189+ private extractValidationAnnotations ( field : InputValueDefinitionNode ) : string [ ] {
190+ if ( ! field . directives || field . directives . length === 0 ) {
191+ return [ ] ;
192+ }
193+
194+ const annotations : string [ ] = [ ] ;
195+
196+ for ( const directive of field . directives ) {
197+ const directiveName = `@${ directive . name . value } ` ;
198+
199+ // Check if it's a validation directive
200+ if ( VALIDATION_DIRECTIVES [ directiveName ] ) {
201+ const annotationName = VALIDATION_DIRECTIVES [ directiveName ] ;
202+
203+ // Parse directive arguments
204+ let annotationParams = '' ;
205+ if ( directive . arguments && directive . arguments . length > 0 ) {
206+ const params = parseDirectiveArgs ( directiveName , Array . from ( directive . arguments ) ) ;
207+ annotationParams = `(${ params . join ( ', ' ) } )` ;
208+ }
209+
210+ annotations . push ( `${ annotationName } ${ annotationParams } ` ) ;
211+ }
212+ }
213+
214+ return annotations ;
215+ }
216+
217+ /**
218+ * Format validation annotations
219+ */
220+ private formatValidationAnnotations ( annotations : string [ ] ) : string [ ] {
221+ // All validation annotations need @field : prefix because they are field annotations, not class annotations
222+ const prefix = '@field:' ;
223+ return annotations . map ( annotation => `${ prefix } ${ annotation } ` ) ;
224+ }
225+
226+ /**
227+ * Add validation annotations to field
228+ */
229+ private addValidationAnnotations (
230+ field : InputValueDefinitionNode ,
231+ _typeInfo : { nullable : boolean }
232+ ) : string [ ] {
233+ const annotations = this . extractValidationAnnotations ( field ) ;
234+
235+ if ( annotations . length === 0 ) {
236+ return [ ] ;
237+ }
238+
239+ return this . formatValidationAnnotations ( annotations ) ;
240+ }
241+
242+ /**
243+ * Extract validation annotations from object type field directives
244+ */
245+ private extractValidationAnnotationsForField ( field : FieldDefinitionNode ) : string [ ] {
246+ if ( ! field . directives || field . directives . length === 0 ) {
247+ return [ ] ;
248+ }
249+
250+ const annotations : string [ ] = [ ] ;
251+
252+ for ( const directive of field . directives ) {
253+ const directiveName = `@${ directive . name . value } ` ;
254+
255+ // Check if it's a validation directive
256+ if ( VALIDATION_DIRECTIVES [ directiveName ] ) {
257+ const annotationName = VALIDATION_DIRECTIVES [ directiveName ] ;
258+
259+ // Parse directive arguments
260+ let annotationParams = '' ;
261+ if ( directive . arguments && directive . arguments . length > 0 ) {
262+ const params = parseDirectiveArgs ( directiveName , Array . from ( directive . arguments ) ) ;
263+ annotationParams = `(${ params . join ( ', ' ) } )` ;
264+ }
265+
266+ annotations . push ( `${ annotationName } ${ annotationParams } ` ) ;
267+ }
268+ }
269+
270+ return annotations ;
271+ }
272+
273+ /**
274+ * Add validation annotations to object type field constructor parameters
275+ */
276+ private addValidationAnnotationsForField (
277+ field : FieldDefinitionNode ,
278+ _typeInfo : { nullable : boolean }
279+ ) : string [ ] {
280+ const annotations = this . extractValidationAnnotationsForField ( field ) ;
281+
282+ if ( annotations . length === 0 ) {
283+ return [ ] ;
284+ }
285+
286+ // For object type fields, annotations are added directly to constructor parameters
287+ return annotations ;
288+ }
289+
180290 protected buildInputTransfomer (
181291 name : string ,
182292 inputValueArray : ReadonlyArray < InputValueDefinitionNode > ,
@@ -187,10 +297,24 @@ ${enumValues}
187297 const initialValue = this . initialValue ( typeToUse . typeName , arg . defaultValue ) ;
188298 const initial = initialValue ? ` = ${ initialValue } ` : typeToUse . nullable ? ' = null' : '' ;
189299
190- return indent (
300+ // Get validation annotations if enabled
301+ const validationAnnotations = this . config . validationAnnotations ?
302+ this . addValidationAnnotations ( arg , typeToUse ) : [ ] ;
303+
304+ // Build field declaration, including annotations
305+ let fieldDeclaration = '' ;
306+ if ( validationAnnotations . length > 0 ) {
307+ // Add validation annotations
308+ fieldDeclaration += validationAnnotations . map ( ann => indent ( ann , 2 ) ) . join ( '\n' ) + '\n' ;
309+ }
310+
311+ // Add field declaration
312+ fieldDeclaration += indent (
191313 `val ${ arg . name . value } : ${ typeToUse . typeName } ${ typeToUse . nullable ? '?' : '' } ${ initial } ` ,
192314 2 ,
193315 ) ;
316+
317+ return fieldDeclaration ;
194318 } )
195319 . join ( ',\n' ) ;
196320 let suppress = '' ;
@@ -252,10 +376,24 @@ ${ctorSet}
252376 }
253377 const typeToUse = this . resolveInputFieldType ( arg . type ) ;
254378
255- return indent (
379+ // Get validation annotations if enabled
380+ const validationAnnotations = this . config . validationAnnotations ?
381+ this . addValidationAnnotationsForField ( arg , typeToUse ) : [ ] ;
382+
383+ // Build field declaration, including annotations
384+ let fieldDeclaration = '' ;
385+ if ( validationAnnotations . length > 0 ) {
386+ // Add validation annotations
387+ fieldDeclaration += validationAnnotations . map ( ann => indent ( ann , 2 ) ) . join ( '\n' ) + '\n' ;
388+ }
389+
390+ // Add field declaration
391+ fieldDeclaration += indent (
256392 `val ${ arg . name . value } : ${ typeToUse . typeName } ${ typeToUse . nullable ? '?' : '' } ` ,
257393 2 ,
258394 ) ;
395+
396+ return fieldDeclaration ;
259397 } )
260398 . join ( ',\n' ) ;
261399
0 commit comments