1from functools import partial
2from typing import Any, Dict, List, Optional, Union
3
4from tartiflette.language.ast import ListTypeNode, NonNullTypeNode
5from tartiflette.language.parsers.lark import parse_to_document
6from tartiflette.schema.schema import GraphQLSchema
7from tartiflette.types.argument import GraphQLArgument
8from tartiflette.types.directive import GraphQLDirective
9from tartiflette.types.enum import (
10    GraphQLEnumType,
11    GraphQLEnumTypeExtension,
12    GraphQLEnumValue,
13)
14from tartiflette.types.field import GraphQLField
15from tartiflette.types.input_field import GraphQLInputField
16from tartiflette.types.input_object import (
17    GraphQLInputObjectType,
18    GraphQLInputObjectTypeExtension,
19)
20from tartiflette.types.interface import (
21    GraphQLInterfaceType,
22    GraphQLInterfaceTypeExtension,
23)
24from tartiflette.types.list import GraphQLList
25from tartiflette.types.non_null import GraphQLNonNull
26from tartiflette.types.object import (
27    GraphQLObjectType,
28    GraphQLObjectTypeExtension,
29)
30from tartiflette.types.scalar import (
31    GraphQLScalarType,
32    GraphQLScalarTypeExtension,
33)
34from tartiflette.types.schema_extension import GraphQLSchemaExtension
35from tartiflette.types.union import GraphQLUnionType, GraphQLUnionTypeExtension
36
37__all__ = ("schema_from_sdl",)
38
39
40def parse_name(
41    name_node: "NameNode", schema: "GraphQLSchema"
42) -> Optional[str]:
43    """
44    Returns the value of an AST name node.
45    :param name_node: AST name node to treat
46    :param schema: the GraphQLSchema instance linked to the engine
47    :type name_node: NameNode
48    :type schema: GraphQLSchema
49    :return: the name value
50    :rtype: Optional[str]
51    """
52    # pylint: disable=unused-argument
53    return name_node.value if name_node else None
54
55
56def parse_named_type(
57    named_type_node: "NamedTypeNode", schema: "GraphQLSchema"
58) -> Optional[str]:
59    """
60    Returns the value of the name of an AST named type node.
61    :param named_type_node: AST named type node to treat
62    :param schema: the GraphQLSchema instance linked to the engine
63    :type named_type_node: NamedTypeNode
64    :type schema: GraphQLSchema
65    :return: the name value
66    :rtype: Optional[str]
67    """
68    if not named_type_node:
69        return None
70    return parse_name(named_type_node.name, schema)
71
72
73def parse_boolean_value(
74    boolean_value_node: "BooleanValueNode", schema: "GraphQLSchema"
75) -> Optional[bool]:
76    """
77    Returns the value of an AST boolean value node.
78    :param boolean_value_node: AST boolean value node to treat
79    :param schema: the GraphQLSchema instance linked to the engine
80    :type boolean_value_node: BooleanValueNode
81    :type schema: GraphQLSchema
82    :return: the boolean value
83    :rtype: Optional[bool]
84    """
85    # pylint: disable=unused-argument
86    return boolean_value_node.value if boolean_value_node else None
87
88
89def parse_enum_value(
90    enum_value_node: "EnumValueNode", schema: "GraphQLSchema"
91) -> Optional[str]:
92    """
93    Returns the value of an AST enum value node.
94    :param enum_value_node: AST enum value node to treat
95    :param schema: the GraphQLSchema instance linked to the engine
96    :type enum_value_node: EnumValueNode
97    :type schema: GraphQLSchema
98    :return: the enum value
99    :rtype: Optional[str]
100    """
101    # pylint: disable=unused-argument
102    return enum_value_node.value if enum_value_node else None
103
104
105def parse_float_value(
106    float_value_node: "FloatValueNode", schema: "GraphQLSchema"
107) -> Optional[float]:
108    """
109    Returns the value of an AST float value node.
110    :param float_value_node: AST float value node to treat
111    :param schema: the GraphQLSchema instance linked to the engine
112    :type float_value_node: FloatValueNode
113    :type schema: GraphQLSchema
114    :return: the float value
115    :rtype: Optional[float]
116    """
117    # pylint: disable=unused-argument
118    return float_value_node.value if float_value_node else None
119
120
121def parse_int_value(
122    int_value_node: "IntValueNode", schema: "GraphQLSchema"
123) -> Optional[int]:
124    """
125    Returns the value of an AST int value node.
126    :param int_value_node: AST int value node to treat
127    :param schema: the GraphQLSchema instance linked to the engine
128    :type int_value_node: IntValueNode
129    :type schema: GraphQLSchema
130    :return: the int value
131    :rtype: Optional[int]
132    """
133    # pylint: disable=unused-argument
134    return int_value_node.value if int_value_node else None
135
136
137def parse_string_value(
138    string_value_node: "StringValueNode", schema: "GraphQLSchema"
139) -> Optional[str]:
140    """
141    Returns the value of an AST string value node.
142    :param string_value_node: AST string value node to treat
143    :param schema: the GraphQLSchema instance linked to the engine
144    :type string_value_node: StringValueNode
145    :type schema: GraphQLSchema
146    :return: the string value
147    :rtype: Optional[str]
148    """
149    # pylint: disable=unused-argument
150    return string_value_node.value if string_value_node else None
151
152
153def parse_list_value(
154    list_value_node: "ListValueNode", schema: "GraphQLSchema"
155) -> Optional[List[Any]]:
156    """
157    Returns the value of an AST list value node.
158    :param list_value_node: AST list value node to treat
159    :param schema: the GraphQLSchema instance linked to the engine
160    :type list_value_node: ListValueNode
161    :type schema: GraphQLSchema
162    :return: the list value
163    :rtype: Optional[List[Any]]
164    """
165    if not list_value_node:
166        return None
167    return [parse_value(value, schema) for value in list_value_node.values]
168
169
170def parse_null_value(
171    null_value_node: "NullValueNode", schema: "GraphQLSchema"
172) -> None:
173    """
174    Returns the value of an AST null value node.
175    :param null_value_node: AST null value node to treat
176    :param schema: the GraphQLSchema instance linked to the engine
177    :type null_value_node: NullValueNode
178    :type schema: GraphQLSchema
179    """
180    # pylint: disable=unused-argument
181    return None
182
183
184def parse_object_value(
185    object_value_node: "ObjectValueNode", schema: "GraphQLSchema"
186) -> Optional[Dict[str, Any]]:
187    """
188    Returns the value of an AST object value node
189    :param object_value_node: AST object value node to treat
190    :param schema: the GraphQLSchema instance linked to the engine
191    :type object_value_node: ObjectValueNode
192    :type schema: GraphQLSchema
193    :return: the object value
194    :rtype: Optional[Dict[str, Any]]
195    """
196    if not object_value_node:
197        return None
198    return {
199        parse_name(field_node.name, schema): parse_value(
200            field_node.value, schema
201        )
202        for field_node in object_value_node.fields
203    }
204
205
206_VALUE_PARSER_MAPPING = {
207    "BooleanValueNode": parse_boolean_value,
208    "EnumValueNode": parse_enum_value,
209    "FloatValueNode": parse_float_value,
210    "IntValueNode": parse_int_value,
211    "ListValueNode": parse_list_value,
212    "NullValueNode": parse_null_value,
213    "ObjectValueNode": parse_object_value,
214    "StringValueNode": parse_string_value,
215}
216
217
218def parse_value(
219    value_node: "ValueNode", schema: "GraphQLSchema"
220) -> Optional[Any]:
221    """
222    Returns the value of an AST value node
223    :param value_node: AST value node to treat
224    :param schema: the GraphQLSchema instance linked to the engine
225    :type value_node: ValueNode
226    :type schema: GraphQLSchema
227    :return: the value
228    :rtype: Optional[Any]
229    """
230    if not value_node:
231        return None
232    return _VALUE_PARSER_MAPPING[value_node.__class__.__name__](
233        value_node, schema
234    )
235
236
237def parse_input_value_definition(
238    input_value_definition_node: "InputValueDefinitionNode",
239    schema: "GraphQLSchema",
240    as_argument_definition: bool = False,
241) -> Optional[Union["GraphQLArgument", "GraphQLInputField"]]:
242    """
243    Computes an AST input value definition node into a GraphQLArgument or
244    GraphQLInputField instance.
245    :param input_value_definition_node: AST input value definition node to
246    treat
247    :param schema: the GraphQLSchema instance linked to the engine
248    :param as_argument_definition: determines whether or not the return type
249    should be a GraphQLArgument or a GraphQLInputField
250    :type input_value_definition_node: InputValueDefinitionNode
251    :type schema: GraphQLSchema
252    :type as_argument_definition: bool
253    :return: the computed GraphQLArgument or GraphQLInputField instance
254    :rtype: Optional[Union[GraphQLArgument, GraphQLInputField]]
255    """
256    if not input_value_definition_node:
257        return None
258
259    init_kwargs = {
260        "name": parse_name(input_value_definition_node.name, schema),
261        "description": parse_name(
262            input_value_definition_node.description, schema
263        ),
264        "gql_type": parse_type(input_value_definition_node.type, schema),
265        "default_value": input_value_definition_node.default_value,
266        "directives": input_value_definition_node.directives,
267    }
268
269    if not as_argument_definition:
270        return GraphQLInputField(**init_kwargs)
271    return GraphQLArgument(
272        **init_kwargs, definition=input_value_definition_node
273    )
274
275
276def parse_arguments_definition(
277    argument_definitions_node: List["InputValueDefinitionNode"],
278    schema: "GraphQLSchema",
279) -> Optional[Dict[str, "GraphQLArgument"]]:
280    """
281    Returns a dictionary of computed GraphQLArgument.
282    :param argument_definitions_node: list of AST input value definition
283    node to treat
284    :param schema: the GraphQLSchema instance linked to the engine
285    :type argument_definitions_node: List[InputValueDefinitionNode]
286    :type schema: GraphQLSchema
287    :return: dictionary of computed GraphQLArgument
288    :rtype: Optional[Dict[str, GraphQLArgument]]
289    """
290    if not argument_definitions_node:
291        return None
292
293    computed_arguments = {}
294    for input_value_definition_node in argument_definitions_node:
295        computed_argument = parse_input_value_definition(
296            input_value_definition_node, schema, as_argument_definition=True
297        )
298        computed_arguments[computed_argument.name] = computed_argument
299    return computed_arguments
300
301
302def parse_operation_type_definition(
303    operation_type_definition_node: "OperationTypeDefinitionNode",
304    schema: "GraphQLSchema",
305) -> None:
306    """
307    Computes the new operation type definition name and update it in the
308    schema.
309    :param operation_type_definition_node: AST operation type definition node
310    to treat
311    :param schema: the GraphQLSchema instance linked to the engine
312    :type operation_type_definition_node: OperationTypeDefinitionNode
313    :type schema: GraphQLSchema
314    """
315    if not operation_type_definition_node:
316        return
317    setattr(
318        schema,
319        f"{operation_type_definition_node.operation_type}_operation_name",
320        parse_named_type(operation_type_definition_node.type, schema),
321    )
322
323
324def parse_operation_type_definitions(
325    operation_type_definitions_node: List["OperationTypeDefinitionNode"],
326    schema: "GraphQLSchema",
327) -> None:
328    """
329    Parses all AST operation type definition node in order to update the
330    schema.
331    :param operation_type_definitions_node: list of AST operation type
332    definition node to treat
333    :param schema: the GraphQLSchema instance linked to the engine
334    :type operation_type_definitions_node: List[OperationTypeDefinitionNode]
335    :type schema: GraphQLSchema
336    """
337    if not operation_type_definitions_node:
338        return
339
340    for operation_type_definition_node in operation_type_definitions_node:
341        parse_operation_type_definition(operation_type_definition_node, schema)
342
343
344def parse_schema_definition(
345    schema_definition_node: "SchemaDefinitionNode", schema: "GraphQLSchema"
346) -> None:
347    """
348    Parses the AST operation type definition nodes from the AST schema
349    definition node.
350    :param schema_definition_node: AST schema definition node to treat
351    :param schema: the GraphQLSchema instance linked to the engine
352    :type schema_definition_node: SchemaDefinitionNode
353    :type schema: GraphQLSchema
354    """
355    if not schema_definition_node:
356        return
357    parse_operation_type_definitions(
358        schema_definition_node.operation_type_definitions, schema
359    )
360    schema.add_schema_directives(schema_definition_node.directives)
361
362
363def parse_scalar_type_definition(
364    scalar_type_definition_node: "ScalarTypeDefinitionNode",
365    schema: "GraphQLSchema",
366) -> Optional["GraphQLScalarType"]:
367    """
368    Computes an AST scalar type definition node into a GraphQLScalarType
369    instance.
370    :param scalar_type_definition_node: AST scalar type definition node to
371    treat
372    :param schema: the GraphQLSchema instance linked to the engine
373    :type scalar_type_definition_node: ScalarTypeDefinitionNode
374    :type schema: GraphQLSchema
375    :return: the computed GraphQLScalarType instance
376    :rtype: Optional[GraphQLScalarType]
377    """
378    if not scalar_type_definition_node:
379        return None
380
381    scalar_type = GraphQLScalarType(
382        name=parse_name(scalar_type_definition_node.name, schema),
383        description=parse_name(
384            scalar_type_definition_node.description, schema
385        ),
386        directives=scalar_type_definition_node.directives,
387    )
388    schema.add_scalar_definition(scalar_type)
389    return scalar_type
390
391
392def parse_implements_interfaces(
393    interfaces_node: List["NamedTypeNode"], schema: "GraphQLSchema"
394) -> Optional[List[str]]:
395    """
396    Returns the list of implemented interface names.
397    :param interfaces_node: list of AST named type node to treat
398    :param schema: the GraphQLSchema instance linked to the engine
399    :type interfaces_node: List[NamedTypeNode]
400    :type schema: GraphQLSchema
401    :return: the list of implemented interface names
402    :rtype: Optional[List[str]]
403    """
404    if not interfaces_node:
405        return None
406
407    return [
408        parse_named_type(interface_node, schema)
409        for interface_node in interfaces_node
410    ]
411
412
413def parse_object_type_definition(
414    object_type_definition_node: "ObjectTypeDefinitionNode",
415    schema: "GraphQLSchema",
416) -> Optional["GraphQLObjectType"]:
417    """
418    Computes an AST object type definition node into a GraphQLObjectType
419    instance.
420    :param object_type_definition_node: AST object type definition node to
421    treat
422    :param schema: the GraphQLSchema instance linked to the engine
423    :type object_type_definition_node: ObjectTypeDefinitionNode
424    :type schema: GraphQLSchema
425    :return: the GraphQLObjectType instance
426    :rtype: Optional[GraphQLObjectType]
427    """
428    if not object_type_definition_node:
429        return None
430
431    object_type = GraphQLObjectType(
432        name=parse_name(object_type_definition_node.name, schema),
433        description=parse_name(
434            object_type_definition_node.description, schema
435        ),
436        interfaces=parse_implements_interfaces(
437            object_type_definition_node.interfaces, schema
438        ),
439        fields=parse_fields_definition(
440            object_type_definition_node.fields, schema
441        ),
442        directives=object_type_definition_node.directives,
443    )
444    schema.add_type_definition(object_type)
445    return object_type
446
447
448def parse_field_definition(
449    field_definition_node: "FieldDefinitionNode", schema: "GraphQLSchema"
450) -> Optional["GraphQLField"]:
451    """
452    Computes an AST field definition node into a GraphQLField instance.
453    :param field_definition_node: AST field definition node to treat
454    :param schema: the GraphQLSchema instance linked to the engine
455    :type field_definition_node: FieldDefinitionNode
456    :type schema: GraphQLSchema
457    :return: the GraphQLField instance
458    :rtype: Optional[GraphQLField]
459    """
460    if not field_definition_node:
461        return None
462
463    return GraphQLField(
464        name=parse_name(field_definition_node.name, schema),
465        description=parse_name(field_definition_node.description, schema),
466        gql_type=parse_type(field_definition_node.type, schema),
467        arguments=parse_arguments_definition(
468            field_definition_node.arguments, schema
469        ),
470        directives=field_definition_node.directives,
471    )
472
473
474def parse_fields_definition(
475    fields_definition_node: List["FieldDefinitionNode"],
476    schema: "GraphQLSchema",
477) -> Optional[Dict[str, "GraphQLField"]]:
478    """
479    Returns a dictionary of computed GraphQLField.
480    :param fields_definition_node: list of AST field definition node to treat
481    :param schema: the GraphQLSchema instance linked to the engine
482    :type fields_definition_node: List[FieldDefinitionNode]
483    :type schema: GraphQLSchema
484    :return: dictionary of computed GraphQLField
485    :rtype: Optional[Dict[str, GraphQLField]]
486    """
487    if not fields_definition_node:
488        return None
489
490    computed_fields = {}
491    for field_definition_node in fields_definition_node:
492        computed_field = parse_field_definition(field_definition_node, schema)
493        computed_fields[computed_field.name] = computed_field
494    return computed_fields
495
496
497def parse_interface_type_definition(
498    interface_type_definition_node: "InterfaceTypeDefinitionNode",
499    schema: "GraphQLSchema",
500) -> Optional["GraphQLInterfaceType"]:
501    """
502    Computes an AST interface type definition node into a GraphQLInterfaceType
503    instance.
504    :param interface_type_definition_node: AST interface type definition node
505    to treat
506    :param schema: the GraphQLSchema instance linked to the engine
507    :type interface_type_definition_node: InterfaceTypeDefinitionNode
508    :type schema: GraphQLSchema
509    :return: the GraphQLInterfaceType instance
510    :rtype: Optional[GraphQLInterfaceType]
511    """
512    if not interface_type_definition_node:
513        return None
514
515    interface_type = GraphQLInterfaceType(
516        name=parse_name(interface_type_definition_node.name, schema),
517        description=parse_name(
518            interface_type_definition_node.description, schema
519        ),
520        fields=parse_fields_definition(
521            interface_type_definition_node.fields, schema
522        ),
523        directives=interface_type_definition_node.directives,
524    )
525    schema.add_type_definition(interface_type)
526    return interface_type
527
528
529def parse_union_member_types(
530    types_node: List["NamedTypeNode"], schema: "GraphQLSchema"
531) -> Optional[List[str]]:
532    """
533    Returns the list of union member type name.
534    :param types_node: list of AST named type node to treat
535    :param schema: the GraphQLSchema instance linked to the engine
536    :type types_node: List[NamedTypeNode]
537    :type schema: GraphQLSchema
538    :return: the list of union member type name
539    :rtype: Optional[List[str]]
540    """
541    if not types_node:
542        return None
543
544    return [
545        parse_named_type(union_member_type_node, schema)
546        for union_member_type_node in types_node
547    ]
548
549
550def parse_union_type_definition(
551    union_type_definition_node: "UnionTypeDefinitionNode",
552    schema: "GraphQLSchema",
553) -> Optional["GraphQLUnionType"]:
554    """
555    Computes an AST union type definition node into a GraphQLUnionType
556    instance.
557    :param union_type_definition_node: AST union type definition node to treat
558    :param schema: the GraphQLSchema instance linked to the engine
559    :type union_type_definition_node: UnionTypeDefinitionNode
560    :type schema: GraphQLSchema
561    :return: the GraphQLUnionType instance
562    :rtype: Optional[GraphQLUnionType]
563    """
564    if not union_type_definition_node:
565        return None
566
567    union_type = GraphQLUnionType(
568        name=parse_name(union_type_definition_node.name, schema),
569        description=parse_name(union_type_definition_node.description, schema),
570        types=parse_union_member_types(
571            union_type_definition_node.types, schema
572        ),
573        directives=union_type_definition_node.directives,
574    )
575    schema.add_type_definition(union_type)
576    return union_type
577
578
579def parse_enum_value_definition(
580    enum_value_definition_node: "EnumValueDefinitionNode",
581    schema: "GraphQLSchema",
582) -> Optional["GraphQLEnumValue"]:
583    """
584    Computes an AST enum value definition node into a GraphQLEnumValue
585    instance.
586    :param enum_value_definition_node: AST enum value definition node to treat
587    :param schema: the GraphQLSchema instance linked to the engine
588    :type enum_value_definition_node: EnumValueDefinitionNode
589    :type schema: GraphQLSchema
590    :return: the GraphQLEnumValue instance
591    :rtype: Optional[GraphQLEnumValue]
592    """
593    if not enum_value_definition_node:
594        return None
595    return GraphQLEnumValue(
596        value=parse_name(enum_value_definition_node.name, schema),
597        description=parse_name(enum_value_definition_node.description, schema),
598        directives=enum_value_definition_node.directives,
599    )
600
601
602def parse_enum_values_definition(
603    enum_values_definition_node: List["EnumValueDefinitionNode"],
604    schema: "GraphQLSchema",
605) -> Optional[List["GraphQLEnumValue"]]:
606    """
607    Returns a list of computed GraphQLEnumValue.
608    :param enum_values_definition_node: list of AST enum value definition node
609    to treat
610    :param schema: the GraphQLSchema instance linked to the engine
611    :type enum_values_definition_node: List[EnumValueDefinitionNode]
612    :type schema: GraphQLSchema
613    :return: list of computed GraphQLEnumValue
614    :rtype: Optional[List[GraphQLEnumValue]]
615    """
616    if not enum_values_definition_node:
617        return None
618
619    return [
620        parse_enum_value_definition(enum_value_definition_node, schema)
621        for enum_value_definition_node in enum_values_definition_node
622    ]
623
624
625def parse_enum_type_definition(
626    enum_type_definition_node: "EnumTypeDefinitionNode",
627    schema: "GraphQLSchema",
628) -> Optional["GraphQLEnumType"]:
629    """
630    Computes an AST enum type definition node into a GraphQLEnumType instance.
631    :param enum_type_definition_node: AST enum type definition node to treat
632    :param schema: the GraphQLSchema instance linked to the engine
633    :type enum_type_definition_node: EnumTypeDefinitionNode
634    :type schema: GraphQLSchema
635    :return: the GraphQLEnumType instance
636    :rtype: Optional[GraphQLEnumType]
637    """
638    if not enum_type_definition_node:
639        return None
640
641    enum_type = GraphQLEnumType(
642        name=parse_name(enum_type_definition_node.name, schema),
643        description=parse_name(enum_type_definition_node.description, schema),
644        values=parse_enum_values_definition(
645            enum_type_definition_node.values, schema
646        ),
647        directives=enum_type_definition_node.directives,
648    )
649    schema.add_enum_definition(enum_type)
650    return enum_type
651
652
653def parse_input_fields_definition(
654    input_fields_definition_node: List["InputValueDefinitionNode"],
655    schema: "GraphQLSchema",
656) -> Optional[Dict[str, "GraphQLInputField"]]:
657    """
658    Returns a dictionary of computed GraphQLInputField.
659    :param input_fields_definition_node: list of AST input value definition
660    node to treat
661    :param schema: the GraphQLSchema instance linked to the engine
662    :type input_fields_definition_node: List[InputValueDefinitionNode]
663    :type schema: GraphQLSchema
664    :return: dictionary of computed GraphQLInputField
665    :rtype: Optional[Dict[str, GraphQLInputField]]
666    """
667    if not input_fields_definition_node:
668        return None
669
670    computed_input_fields = {}
671    for input_field_definition_node in input_fields_definition_node:
672        input_value_definition = parse_input_value_definition(
673            input_field_definition_node, schema
674        )
675        computed_input_fields[
676            input_value_definition.name
677        ] = input_value_definition
678    return computed_input_fields
679
680
681def parse_input_object_type_definition(
682    input_object_type_definition_node: "InputObjectTypeDefinitionNode",
683    schema: "GraphQLSchema",
684) -> Optional["GraphQLInputObjectType"]:
685    """
686    Computes an AST input object type definition node into a
687    GraphQLInputObjectType instance.
688    :param input_object_type_definition_node: AST input object type
689    definition node to treat
690    :param schema: the GraphQLSchema instance linked to the engine
691    :type input_object_type_definition_node: InputObjectTypeDefinitionNode
692    :type schema: GraphQLSchema
693    :return: the GraphQLInputObjectType instance
694    :rtype: Optional[GraphQLInputObjectType]
695    """
696    if not input_object_type_definition_node:
697        return None
698
699    input_object_type = GraphQLInputObjectType(
700        name=parse_name(input_object_type_definition_node.name, schema),
701        description=parse_name(
702            input_object_type_definition_node.description, schema
703        ),
704        fields=parse_input_fields_definition(
705            input_object_type_definition_node.fields, schema
706        ),
707        directives=input_object_type_definition_node.directives,
708    )
709    schema.add_type_definition(input_object_type)
710    return input_object_type
711
712
713def parse_type(
714    type_node: "TypeNode", schema: "GraphQLSchema"
715) -> Union["GraphQLList", "GraphQLNonNull", str]:
716    """
717    Computes an AST type node into its GraphQL representation.
718    :param type_node: AST type node to treat
719    :param schema: the GraphQLSchema instance linked to the engine
720    :type type_node: TypeNode
721    :type schema: GraphQLSchema
722    :return: the GraphQL representation of the type node
723    :rtype: Union[GraphQLList, GraphQLNonNull, str]
724    """
725    inner_type_node = type_node
726    type_wrappers = []
727    while isinstance(inner_type_node, (NonNullTypeNode, ListTypeNode)):
728        if isinstance(inner_type_node, ListTypeNode):
729            type_wrappers.append(partial(GraphQLList, schema=schema))
730        elif isinstance(inner_type_node, NonNullTypeNode):
731            type_wrappers.append(
732                partial(partial(GraphQLNonNull, schema=schema))
733            )
734        inner_type_node = inner_type_node.type
735
736    graphql_type = parse_named_type(inner_type_node, schema)
737    for type_wrapper in reversed(type_wrappers):
738        graphql_type = type_wrapper(gql_type=graphql_type)
739    return graphql_type
740
741
742def parse_directive_definition(
743    directive_definition_node: "DirectiveDefinitionNode",
744    schema: "GraphQLSchema",
745) -> Optional["GraphQLDirective"]:
746    """
747    Computes an AST directive definition node into a GraphQLDirective instance.
748    :param directive_definition_node: AST directive definition node to treat
749    :param schema: the GraphQLSchema instance linked to the engine
750    :type directive_definition_node: DirectiveDefinitionNode
751    :type schema: GraphQLSchema
752    :return: the GraphQLDirective instance
753    :rtype: Optional[GraphQLDirective]
754    """
755    if not directive_definition_node:
756        return None
757    directive = GraphQLDirective(
758        name=parse_name(directive_definition_node.name, schema),
759        description=parse_name(directive_definition_node.description, schema),
760        locations=[
761            location.value for location in directive_definition_node.locations
762        ],
763        arguments=parse_arguments_definition(
764            directive_definition_node.arguments, schema
765        ),
766    )
767    schema.add_directive_definition(directive)
768    return directive
769
770
771def parse_enum_type_extension(
772    enum_type_extension_node: "EnumTypeExtensionNode", schema: "GraphQLSchema"
773) -> "GraphQLEnumTypeExtension":
774
775    enum_extension = GraphQLEnumTypeExtension(
776        name=parse_name(enum_type_extension_node.name, schema),
777        directives=enum_type_extension_node.directives,
778        values=parse_enum_values_definition(
779            enum_type_extension_node.values, schema
780        ),
781    )
782
783    schema.add_extension(enum_extension)
784
785    return enum_extension
786
787
788def parse_input_object_type_extension(
789    input_object_type_extension_node: "InputObjectTypeExtensionNode",
790    schema: "GraphQLSchema",
791) -> "GraphQLInputObjectTypeExtension":
792
793    input_object_extenstion = GraphQLInputObjectTypeExtension(
794        name=parse_name(input_object_type_extension_node.name, schema),
795        directives=input_object_type_extension_node.directives,
796        input_fields=parse_input_fields_definition(
797            input_object_type_extension_node.fields, schema
798        ),
799    )
800
801    schema.add_extension(input_object_extenstion)
802
803    return input_object_extenstion
804
805
806def parse_object_type_extension(
807    object_type_extension_node: "ObjectTypeExtensionNode",
808    schema: "GraphQLSchema",
809) -> "GraphQLObjectTypeExtension":
810
811    object_extension = GraphQLObjectTypeExtension(
812        name=parse_name(object_type_extension_node.name, schema),
813        fields=parse_fields_definition(
814            object_type_extension_node.fields, schema
815        ),
816        directives=object_type_extension_node.directives,
817        interfaces=parse_implements_interfaces(
818            object_type_extension_node.interfaces, schema
819        ),
820    )
821
822    schema.add_extension(object_extension)
823
824    return object_extension
825
826
827def parse_interface_type_extension(
828    interface_type_extension_node: "InterfaceTypeExtensionNode",
829    schema: "GraphQLSchema",
830) -> "GraphQLInterfaceTypeExtension":
831
832    interface_extension = GraphQLInterfaceTypeExtension(
833        name=parse_name(interface_type_extension_node.name, schema),
834        fields=parse_fields_definition(
835            interface_type_extension_node.fields, schema
836        ),
837        directives=interface_type_extension_node.directives,
838    )
839
840    schema.add_extension(interface_extension)
841
842    return interface_extension
843
844
845def parse_scalar_type_extension(
846    scalar_type_extension_node: "ScalarTypeExtensionNode",
847    schema: "GraphQLSchema",
848) -> "GraphQLScalarTypeExtension":
849
850    scalar_extension = GraphQLScalarTypeExtension(
851        name=parse_name(scalar_type_extension_node.name, schema),
852        directives=scalar_type_extension_node.directives,
853    )
854
855    schema.add_extension(scalar_extension)
856
857    return scalar_extension
858
859
860def parse_union_type_extension(
861    union_type_extension_node: "UnionTypeExtensionNode",
862    schema: "GraphQLSchema",
863) -> "GraphQLUnionTypeExtension":
864
865    union_extension = GraphQLUnionTypeExtension(
866        name=parse_name(union_type_extension_node.name, schema),
867        directives=union_type_extension_node.directives,
868        types=parse_union_member_types(
869            union_type_extension_node.types, schema
870        ),
871    )
872
873    schema.add_extension(union_extension)
874
875    return union_extension
876
877
878def parse_schema_extension(
879    schema_extension_node: "SchemaExtensionNode", schema: "GraphQLSchema"
880) -> "GraphQLSchemaExtension":
881    schema_extension = GraphQLSchemaExtension(
882        directives=schema_extension_node.directives,
883        operations={
884            x.operation_type: parse_named_type(x.type, schema)
885            for x in schema_extension_node.operation_type_definitions
886        },
887    )
888
889    schema.add_extension(schema_extension)
890
891    return schema_extension
892
893
894_DEFINITION_PARSER_MAPPING = {
895    "SchemaDefinitionNode": parse_schema_definition,
896    "ScalarTypeDefinitionNode": parse_scalar_type_definition,
897    "ObjectTypeDefinitionNode": parse_object_type_definition,
898    "InterfaceTypeDefinitionNode": parse_interface_type_definition,
899    "UnionTypeDefinitionNode": parse_union_type_definition,
900    "EnumTypeDefinitionNode": parse_enum_type_definition,
901    "InputObjectTypeDefinitionNode": parse_input_object_type_definition,
902    "DirectiveDefinitionNode": parse_directive_definition,
903    "EnumTypeExtensionNode": parse_enum_type_extension,
904    "InputObjectTypeExtensionNode": parse_input_object_type_extension,
905    "ObjectTypeExtensionNode": parse_object_type_extension,
906    "InterfaceTypeExtensionNode": parse_interface_type_extension,
907    "ScalarTypeExtensionNode": parse_scalar_type_extension,
908    "UnionTypeExtensionNode": parse_union_type_extension,
909    "SchemaExtensionNode": parse_schema_extension,
910}
911
912
913def parse_definition(
914    definition_node: "DefinitionNode", schema: "GraphQLSchema"
915) -> Any:
916    """
917    Attempts to parses and computes an AST definition node.
918    :param definition_node: AST definition node to treat
919    :param schema: the GraphQLSchema instance linked to the engine
920    :type definition_node: DefinitionNode
921    :type schema: GraphQLSchema
922    :return: the computed result
923    :rtype: Any
924    """
925    definition_parser = _DEFINITION_PARSER_MAPPING.get(
926        definition_node.__class__.__name__
927    )
928    if definition_parser is None:
929        return None
930    return definition_parser(definition_node, schema)
931
932
933def schema_from_document(
934    document_node: "DocumentNode", schema_name: str
935) -> "GraphQLSchema":
936    """
937    Parses all AST definition node from the AST document node in order to build
938    the GraphQLSchema.
939    :param document_node: AST document node to treat
940    :param schema_name: name of the schema to build
941    :type document_node: DocumentNode
942    :type schema_name: str
943    :return: build GraphQLSchema
944    :rtype: GraphQLSchema
945    """
946    schema = GraphQLSchema(name=schema_name)
947    for definition_node in document_node.definitions:
948        parse_definition(definition_node, schema)
949    return schema
950
951
952def schema_from_sdl(
953    sdl: Union[str, bytes], schema_name: str
954) -> "GraphQLSchema":
955    """
956    Parse the SDL into an AST document node before validating it and building a
957    GraphQL Schema instance upon it.
958    :param sdl: sdl to parse
959    :param schema_name: name of the schema to build
960    :type sdl: Union[str, bytes]
961    :type schema_name: str
962    :return: build GraphQLSchema
963    :rtype: GraphQLSchema
964    """
965    document_node = parse_to_document(sdl)
966    # TODO: implements the `validate_document` function
967    # errors = validate_document(document)
968    # if errors:
969    #     raise Something(errors)
970    return schema_from_document(document_node, schema_name=schema_name)
971