@@ -45,6 +45,7 @@ class SchemaParser internal constructor(
4545 private val inputObjectDefinitions = (definitions.filterIsInstance<InputObjectTypeDefinition >() - inputExtensionDefinitions)
4646 private val enumDefinitions = definitions.filterIsInstance<EnumTypeDefinition >()
4747 private val interfaceDefinitions = definitions.filterIsInstance<InterfaceTypeDefinition >()
48+ private val directiveDefinitions = definitions.filterIsInstance<DirectiveDefinition >()
4849
4950 private val unionDefinitions = definitions.filterIsInstance<UnionTypeDefinition >()
5051
@@ -82,6 +83,8 @@ class SchemaParser internal constructor(
8283 val unions = unionDefinitions.map { createUnionObject(it, objects) }
8384 val enums = enumDefinitions.map { createEnumObject(it) }
8485
86+ val directives = directiveDefinitions.map { createDirective(it, inputObjects) }.toSet()
87+
8588 // Assign type resolver to interfaces now that we know all of the object types
8689 interfaces.forEach { codeRegistryBuilder.typeResolver(it, InterfaceTypeResolver (dictionary.inverse(), it)) }
8790 unions.forEach { codeRegistryBuilder.typeResolver(it, UnionTypeResolver (dictionary.inverse(), it)) }
@@ -101,7 +104,7 @@ class SchemaParser internal constructor(
101104 val additionalObjects = objects.filter { o -> o != query && o != subscription && o != mutation }
102105
103106 val types = (additionalObjects.toSet() as Set <GraphQLType >) + inputObjects + enums + interfaces + unions
104- return SchemaObjects (query, mutation, subscription, types, codeRegistryBuilder, rootInfo.getDescription())
107+ return SchemaObjects (query, mutation, subscription, types, directives, codeRegistryBuilder, rootInfo.getDescription())
105108 }
106109
107110 /* *
@@ -123,6 +126,7 @@ class SchemaParser internal constructor(
123126 .description(getDocumentation(objectDefinition, options))
124127
125128 builder.withDirectives(* buildDirectives(objectDefinition.directives, Introspection .DirectiveLocation .OBJECT ))
129+ builder.withAppliedDirectives(* buildAppliedDirectives(objectDefinition.directives))
126130
127131 objectDefinition.implements.forEach { implementsDefinition ->
128132 val interfaceName = (implementsDefinition as TypeName ).name
@@ -163,6 +167,7 @@ class SchemaParser internal constructor(
163167 .description(getDocumentation(definition, options))
164168
165169 builder.withDirectives(* buildDirectives(definition.directives, Introspection .DirectiveLocation .INPUT_OBJECT ))
170+ builder.withAppliedDirectives(* buildAppliedDirectives(definition.directives))
166171
167172 referencingInputObjects.add(definition.name)
168173
@@ -175,6 +180,7 @@ class SchemaParser internal constructor(
175180 .apply { inputDefinition.defaultValue?.let { v -> defaultValueLiteral(v) } }
176181 .type(determineInputType(inputDefinition.type, inputObjects, referencingInputObjects))
177182 .withDirectives(* buildDirectives(inputDefinition.directives, Introspection .DirectiveLocation .INPUT_FIELD_DEFINITION ))
183+ .withAppliedDirectives(* buildAppliedDirectives(inputDefinition.directives))
178184 builder.field(fieldBuilder.build())
179185 }
180186 }
@@ -194,20 +200,23 @@ class SchemaParser internal constructor(
194200 .description(getDocumentation(definition, options))
195201
196202 builder.withDirectives(* buildDirectives(definition.directives, Introspection .DirectiveLocation .ENUM ))
203+ builder.withAppliedDirectives(* buildAppliedDirectives(definition.directives))
197204
198205 definition.enumValueDefinitions.forEach { enumDefinition ->
199206 val enumName = enumDefinition.name
200207 val enumValue = type.unwrap().enumConstants.find { (it as Enum <* >).name == enumName }
201208 ? : throw SchemaError (" Expected value for name '$enumName ' in enum '${type.unwrap().simpleName} ' but found none!" )
202209
203210 val enumValueDirectives = buildDirectives(enumDefinition.directives, Introspection .DirectiveLocation .ENUM_VALUE )
211+ val enumValueAppliedDirectives = buildAppliedDirectives(enumDefinition.directives)
204212 getDeprecated(enumDefinition.directives).let {
205213 val enumValueDefinition = GraphQLEnumValueDefinition .newEnumValueDefinition()
206214 .name(enumName)
207215 .description(getDocumentation(enumDefinition, options))
208216 .value(enumValue)
209217 .deprecationReason(it)
210218 .withDirectives(* enumValueDirectives)
219+ .withAppliedDirectives(* enumValueAppliedDirectives)
211220 .definition(enumDefinition)
212221 .build()
213222
@@ -226,6 +235,7 @@ class SchemaParser internal constructor(
226235 .description(getDocumentation(interfaceDefinition, options))
227236
228237 builder.withDirectives(* buildDirectives(interfaceDefinition.directives, Introspection .DirectiveLocation .INTERFACE ))
238+ builder.withAppliedDirectives(* buildAppliedDirectives(interfaceDefinition.directives))
229239
230240 interfaceDefinition.fieldDefinitions.forEach { fieldDefinition ->
231241 builder.field { field -> createField(field, fieldDefinition, inputObjects) }
@@ -247,6 +257,7 @@ class SchemaParser internal constructor(
247257 .description(getDocumentation(definition, options))
248258
249259 builder.withDirectives(* buildDirectives(definition.directives, Introspection .DirectiveLocation .UNION ))
260+ builder.withAppliedDirectives(* buildAppliedDirectives(definition.directives))
250261
251262 getLeafUnionObjects(definition, types).forEach { builder.possibleType(it) }
252263 return schemaGeneratorDirectiveHelper.onUnion(builder.build(), schemaDirectiveParameters)
@@ -288,14 +299,44 @@ class SchemaParser internal constructor(
288299 .type(determineInputType(argumentDefinition.type, inputObjects, setOf ()))
289300 .apply { argumentDefinition.defaultValue?.let { defaultValueLiteral(it) } }
290301 .withDirectives(* buildDirectives(argumentDefinition.directives, Introspection .DirectiveLocation .ARGUMENT_DEFINITION ))
302+ .withAppliedDirectives(* buildAppliedDirectives(argumentDefinition.directives))
291303
292304 field.argument(argumentBuilder.build())
293305 }
294306 field.withDirectives(* buildDirectives(fieldDefinition.directives, Introspection .DirectiveLocation .FIELD_DEFINITION ))
307+ field.withAppliedDirectives(* buildAppliedDirectives(fieldDefinition.directives))
295308
296309 return field
297310 }
298311
312+ private fun createDirective (definition : DirectiveDefinition , inputObjects : List <GraphQLInputObjectType >): GraphQLDirective {
313+ val locations = definition.directiveLocations.map { Introspection .DirectiveLocation .valueOf(it.name) }.toTypedArray()
314+
315+ val graphQLDirective = GraphQLDirective .newDirective()
316+ .name(definition.name)
317+ .description(getDocumentation(definition, options))
318+ .definition(definition)
319+ .comparatorRegistry(runtimeWiring.comparatorRegistry)
320+ .validLocations(* locations)
321+ .repeatable(definition.isRepeatable)
322+ .apply {
323+ definition.inputValueDefinitions.forEach { arg ->
324+ argument(GraphQLArgument .newArgument()
325+ .name(arg.name)
326+ .definition(arg)
327+ .description(getDocumentation(arg, options))
328+ .type(determineInputType(arg.type, inputObjects, setOf ()))
329+ .apply { arg.defaultValue?.let { defaultValueLiteral(it) } }
330+ .withDirectives(* buildDirectives(arg.directives, Introspection .DirectiveLocation .ARGUMENT_DEFINITION ))
331+ .withAppliedDirectives(* buildAppliedDirectives(arg.directives))
332+ .build())
333+ }
334+ }
335+ .build()
336+
337+ return graphQLDirective
338+ }
339+
299340 private fun buildDirectives (directives : List <Directive >, directiveLocation : Introspection .DirectiveLocation ): Array <GraphQLDirective > {
300341 val names = mutableSetOf<String >()
301342
@@ -326,14 +367,43 @@ class SchemaParser internal constructor(
326367 return output.toTypedArray()
327368 }
328369
370+ private fun buildAppliedDirectives (directives : List <Directive >): Array <GraphQLAppliedDirective > {
371+ val names = mutableSetOf<String >()
372+
373+ val output = mutableListOf<GraphQLAppliedDirective >()
374+ for (directive in directives) {
375+ if (! names.contains(directive.name)) {
376+ names.add(directive.name)
377+ val graphQLDirective = GraphQLAppliedDirective .newDirective()
378+ .name(directive.name)
379+ .description(getDocumentation(directive, options))
380+ .comparatorRegistry(runtimeWiring.comparatorRegistry)
381+ .apply {
382+ directive.arguments.forEach { arg ->
383+ argument(GraphQLAppliedDirectiveArgument .newArgument()
384+ .name(arg.name)
385+ .type(buildDirectiveInputType(arg.value))
386+ .valueLiteral(arg.value)
387+ .build())
388+ }
389+ }
390+ .build()
391+
392+ output.add(graphQLDirective)
393+ }
394+ }
395+
396+ return output.toTypedArray()
397+ }
398+
329399 private fun buildDirectiveInputType (value : Value <* >): GraphQLInputType ? {
330- when (value) {
331- is NullValue -> return Scalars .GraphQLString
332- is FloatValue -> return Scalars .GraphQLFloat
333- is StringValue -> return Scalars .GraphQLString
334- is IntValue -> return Scalars .GraphQLInt
335- is BooleanValue -> return Scalars .GraphQLBoolean
336- is ArrayValue -> return GraphQLList .list(buildDirectiveInputType(getArrayValueWrappedType(value)))
400+ return when (value) {
401+ is NullValue -> Scalars .GraphQLString
402+ is FloatValue -> Scalars .GraphQLFloat
403+ is StringValue -> Scalars .GraphQLString
404+ is IntValue -> Scalars .GraphQLInt
405+ is BooleanValue -> Scalars .GraphQLBoolean
406+ is ArrayValue -> GraphQLList .list(buildDirectiveInputType(getArrayValueWrappedType(value)))
337407 else -> throw SchemaError (" Directive values of type '${value::class .simpleName} ' are not supported yet." )
338408 }
339409 }
@@ -448,14 +518,10 @@ class SchemaParser internal constructor(
448518 * indicating no deprecation directive was found within the directives list.
449519 */
450520 private fun getDeprecated (directives : List <Directive >): String? =
451- getDirective( directives, " deprecated" ) ?.let { directive ->
521+ directives.find { it.name == " deprecated" } ?.let { directive ->
452522 (directive.arguments.find { it.name == " reason" }?.value as ? StringValue )?.value
453523 ? : DEFAULT_DEPRECATION_MESSAGE
454524 }
455-
456- private fun getDirective (directives : List <Directive >, name : String ): Directive ? = directives.find {
457- it.name == name
458- }
459525}
460526
461527class SchemaError (message : String , cause : Throwable ? = null ) : RuntimeException(message, cause)
0 commit comments