@@ -45,6 +45,7 @@ class SchemaParser internal constructor(
45
45
private val inputObjectDefinitions = (definitions.filterIsInstance<InputObjectTypeDefinition >() - inputExtensionDefinitions)
46
46
private val enumDefinitions = definitions.filterIsInstance<EnumTypeDefinition >()
47
47
private val interfaceDefinitions = definitions.filterIsInstance<InterfaceTypeDefinition >()
48
+ private val directiveDefinitions = definitions.filterIsInstance<DirectiveDefinition >()
48
49
49
50
private val unionDefinitions = definitions.filterIsInstance<UnionTypeDefinition >()
50
51
@@ -82,6 +83,8 @@ class SchemaParser internal constructor(
82
83
val unions = unionDefinitions.map { createUnionObject(it, objects) }
83
84
val enums = enumDefinitions.map { createEnumObject(it) }
84
85
86
+ val directives = directiveDefinitions.map { createDirective(it, inputObjects) }.toSet()
87
+
85
88
// Assign type resolver to interfaces now that we know all of the object types
86
89
interfaces.forEach { codeRegistryBuilder.typeResolver(it, InterfaceTypeResolver (dictionary.inverse(), it)) }
87
90
unions.forEach { codeRegistryBuilder.typeResolver(it, UnionTypeResolver (dictionary.inverse(), it)) }
@@ -101,7 +104,7 @@ class SchemaParser internal constructor(
101
104
val additionalObjects = objects.filter { o -> o != query && o != subscription && o != mutation }
102
105
103
106
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())
105
108
}
106
109
107
110
/* *
@@ -123,6 +126,7 @@ class SchemaParser internal constructor(
123
126
.description(getDocumentation(objectDefinition, options))
124
127
125
128
builder.withDirectives(* buildDirectives(objectDefinition.directives, Introspection .DirectiveLocation .OBJECT ))
129
+ builder.withAppliedDirectives(* buildAppliedDirectives(objectDefinition.directives))
126
130
127
131
objectDefinition.implements.forEach { implementsDefinition ->
128
132
val interfaceName = (implementsDefinition as TypeName ).name
@@ -163,6 +167,7 @@ class SchemaParser internal constructor(
163
167
.description(getDocumentation(definition, options))
164
168
165
169
builder.withDirectives(* buildDirectives(definition.directives, Introspection .DirectiveLocation .INPUT_OBJECT ))
170
+ builder.withAppliedDirectives(* buildAppliedDirectives(definition.directives))
166
171
167
172
referencingInputObjects.add(definition.name)
168
173
@@ -175,6 +180,7 @@ class SchemaParser internal constructor(
175
180
.apply { inputDefinition.defaultValue?.let { v -> defaultValueLiteral(v) } }
176
181
.type(determineInputType(inputDefinition.type, inputObjects, referencingInputObjects))
177
182
.withDirectives(* buildDirectives(inputDefinition.directives, Introspection .DirectiveLocation .INPUT_FIELD_DEFINITION ))
183
+ .withAppliedDirectives(* buildAppliedDirectives(inputDefinition.directives))
178
184
builder.field(fieldBuilder.build())
179
185
}
180
186
}
@@ -194,20 +200,23 @@ class SchemaParser internal constructor(
194
200
.description(getDocumentation(definition, options))
195
201
196
202
builder.withDirectives(* buildDirectives(definition.directives, Introspection .DirectiveLocation .ENUM ))
203
+ builder.withAppliedDirectives(* buildAppliedDirectives(definition.directives))
197
204
198
205
definition.enumValueDefinitions.forEach { enumDefinition ->
199
206
val enumName = enumDefinition.name
200
207
val enumValue = type.unwrap().enumConstants.find { (it as Enum <* >).name == enumName }
201
208
? : throw SchemaError (" Expected value for name '$enumName ' in enum '${type.unwrap().simpleName} ' but found none!" )
202
209
203
210
val enumValueDirectives = buildDirectives(enumDefinition.directives, Introspection .DirectiveLocation .ENUM_VALUE )
211
+ val enumValueAppliedDirectives = buildAppliedDirectives(enumDefinition.directives)
204
212
getDeprecated(enumDefinition.directives).let {
205
213
val enumValueDefinition = GraphQLEnumValueDefinition .newEnumValueDefinition()
206
214
.name(enumName)
207
215
.description(getDocumentation(enumDefinition, options))
208
216
.value(enumValue)
209
217
.deprecationReason(it)
210
218
.withDirectives(* enumValueDirectives)
219
+ .withAppliedDirectives(* enumValueAppliedDirectives)
211
220
.definition(enumDefinition)
212
221
.build()
213
222
@@ -226,6 +235,7 @@ class SchemaParser internal constructor(
226
235
.description(getDocumentation(interfaceDefinition, options))
227
236
228
237
builder.withDirectives(* buildDirectives(interfaceDefinition.directives, Introspection .DirectiveLocation .INTERFACE ))
238
+ builder.withAppliedDirectives(* buildAppliedDirectives(interfaceDefinition.directives))
229
239
230
240
interfaceDefinition.fieldDefinitions.forEach { fieldDefinition ->
231
241
builder.field { field -> createField(field, fieldDefinition, inputObjects) }
@@ -247,6 +257,7 @@ class SchemaParser internal constructor(
247
257
.description(getDocumentation(definition, options))
248
258
249
259
builder.withDirectives(* buildDirectives(definition.directives, Introspection .DirectiveLocation .UNION ))
260
+ builder.withAppliedDirectives(* buildAppliedDirectives(definition.directives))
250
261
251
262
getLeafUnionObjects(definition, types).forEach { builder.possibleType(it) }
252
263
return schemaGeneratorDirectiveHelper.onUnion(builder.build(), schemaDirectiveParameters)
@@ -288,14 +299,44 @@ class SchemaParser internal constructor(
288
299
.type(determineInputType(argumentDefinition.type, inputObjects, setOf ()))
289
300
.apply { argumentDefinition.defaultValue?.let { defaultValueLiteral(it) } }
290
301
.withDirectives(* buildDirectives(argumentDefinition.directives, Introspection .DirectiveLocation .ARGUMENT_DEFINITION ))
302
+ .withAppliedDirectives(* buildAppliedDirectives(argumentDefinition.directives))
291
303
292
304
field.argument(argumentBuilder.build())
293
305
}
294
306
field.withDirectives(* buildDirectives(fieldDefinition.directives, Introspection .DirectiveLocation .FIELD_DEFINITION ))
307
+ field.withAppliedDirectives(* buildAppliedDirectives(fieldDefinition.directives))
295
308
296
309
return field
297
310
}
298
311
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
+
299
340
private fun buildDirectives (directives : List <Directive >, directiveLocation : Introspection .DirectiveLocation ): Array <GraphQLDirective > {
300
341
val names = mutableSetOf<String >()
301
342
@@ -326,14 +367,43 @@ class SchemaParser internal constructor(
326
367
return output.toTypedArray()
327
368
}
328
369
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
+
329
399
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)))
337
407
else -> throw SchemaError (" Directive values of type '${value::class .simpleName} ' are not supported yet." )
338
408
}
339
409
}
@@ -448,14 +518,10 @@ class SchemaParser internal constructor(
448
518
* indicating no deprecation directive was found within the directives list.
449
519
*/
450
520
private fun getDeprecated (directives : List <Directive >): String? =
451
- getDirective( directives, " deprecated" ) ?.let { directive ->
521
+ directives.find { it.name == " deprecated" } ?.let { directive ->
452
522
(directive.arguments.find { it.name == " reason" }?.value as ? StringValue )?.value
453
523
? : DEFAULT_DEPRECATION_MESSAGE
454
524
}
455
-
456
- private fun getDirective (directives : List <Directive >, name : String ): Directive ? = directives.find {
457
- it.name == name
458
- }
459
525
}
460
526
461
527
class SchemaError (message : String , cause : Throwable ? = null ) : RuntimeException(message, cause)
0 commit comments