1from typing import List, Optional, Union
2
3from tartiflette.coercers.common import Path
4from tartiflette.language.ast import (
5    ArgumentNode,
6    BooleanValueNode,
7    DirectiveNode,
8    DocumentNode,
9    EnumValueNode,
10    FieldNode,
11    FloatValueNode,
12    FragmentDefinitionNode,
13    FragmentSpreadNode,
14    InlineFragmentNode,
15    IntValueNode,
16    ListTypeNode,
17    ListValueNode,
18    Location,
19    NamedTypeNode,
20    NameNode,
21    NonNullTypeNode,
22    NullValueNode,
23    ObjectFieldNode,
24    ObjectValueNode,
25    OperationDefinitionNode,
26    SelectionSetNode,
27    StringValueNode,
28    VariableDefinitionNode,
29    VariableNode,
30)
31from tartiflette.language.validators import Validators
32from tartiflette.language.validators.query import RULE_SET
33from tartiflette.language.validators.query.utils import (
34    get_schema_field_type_name,
35)
36
37__all__ = ("document_from_ast_json",)
38
39
40def _parse_location(location_ast: dict) -> "Location":
41    """
42    Creates and returns a Location instance from a location's JSON AST
43    libgraphqlparser representation.
44    :param location_ast: location's JSON AST libgraphqlparser representation
45    :type location_ast: dict
46    :return: a Location instance equivalent to the JSON AST representation
47    :rtype: Location
48    """
49    return Location(
50        line=location_ast["start"]["line"],
51        column=location_ast["start"]["column"],
52        line_end=location_ast["end"]["line"],
53        column_end=location_ast["end"]["column"],
54    )
55
56
57def _parse_name(name_ast: dict) -> "NameNode":
58    """
59    Creates and returns a NameNode instance from a name's JSON AST
60    libgraphqlparser representation.
61    :param name_ast: name's JSON AST libgraphqlparser representation
62    :type name_ast: dict
63    :return: a NameNode instance equivalent to the JSON AST representation
64    :rtype: NameNode
65    """
66    return NameNode(
67        value=name_ast["value"], location=_parse_location(name_ast["loc"])
68    )
69
70
71def _parse_named_type(named_type_ast: dict) -> "NamedTypeNode":
72    """
73    Creates and returns a NamedTypeNode instance from a named type's JSON AST
74    libgraphqlparser representation.
75    :param named_type_ast: named type's JSON AST libgraphqlparser
76    representation
77    :type named_type_ast: dict
78    :return: a NamedTypeNode instance equivalent to the JSON AST representation
79    :rtype: NamedTypeNode
80    """
81    return NamedTypeNode(
82        name=_parse_name(named_type_ast["name"]),
83        location=_parse_location(named_type_ast["loc"]),
84    )
85
86
87def _parse_variable(
88    variable_ast: dict, validators: Validators, *_
89) -> "VariableNode":
90    """
91    Creates and returns a VariableNode instance from a variable's JSON AST
92    libgraphqlparser representation.
93    :param variable_ast: variable's JSON AST libgraphqlparser representation
94    :type variable_ast: dict
95    :param validators: the validators to use in order to validate this definition
96    :type validators: Validators
97    :param _: Ignored parameters
98    :return: a VariableNode instance equivalent to the JSON AST representation
99    :rtype: VariableNode
100    """
101
102    variable = VariableNode(
103        name=_parse_name(variable_ast["name"]),
104        location=_parse_location(variable_ast["loc"]),
105    )
106
107    if not validators.ctx.get("in_variable_definitions", False):
108        if validators.ctx["in_operation"]:
109            validators.ctx["per_operation"][
110                validators.ctx["current_operation_name"]
111            ].setdefault("used_vars", []).append(variable)
112        else:
113            validators.ctx["per_fragment"][
114                validators.ctx["current_fragment_name"]
115            ].setdefault("used_vars", []).append(variable)
116
117    return variable
118
119
120def _parse_boolean_value(boolean_value_ast: dict, *_) -> "BooleanValueNode":
121    """
122    Creates and returns a BooleanValueNode instance from a boolean value's JSON
123    AST libgraphqlparser representation.
124    :param boolean_value_ast: boolean value's JSON AST libgraphqlparser
125    representation
126    :param _: Ignored parameter
127    :type boolean_value_ast: dict
128    :return: a BooleanValueNode instance equivalent to the JSON AST
129    representation
130    :rtype: BooleanValueNode
131    """
132    return BooleanValueNode(
133        value=boolean_value_ast["value"],
134        location=_parse_location(boolean_value_ast["loc"]),
135    )
136
137
138def _parse_enum_value(enum_value_ast: dict, *_) -> "EnumValueNode":
139    """
140    Creates and returns an EnumValueNode instance from an enum value's JSON AST
141    libgraphqlparser representation.
142    :param enum_value_ast: enum value's JSON AST libgraphqlparser
143    representation
144    :param _: Ignored parameter
145    :type enum_value_ast: dict
146    :return: an EnumValueNode instance equivalent to the JSON AST
147    representation
148    :rtype: EnumValueNode
149    """
150    return EnumValueNode(
151        value=enum_value_ast["value"],
152        location=_parse_location(enum_value_ast["loc"]),
153    )
154
155
156def _parse_float_value(float_value_ast: dict, *_) -> "FloatValueNode":
157    """
158    Creates and returns a FloatValueNode instance from a float value's JSON AST
159    libgraphqlparser representation.
160    :param float_value_ast: float value's JSON AST libgraphqlparser
161    representation
162    :param _: Ignored parameter
163    :type float_value_ast: dict
164    :return: a FloatValueNode instance equivalent to the JSON AST
165    representation
166    :rtype: FloatValueNode
167    """
168    return FloatValueNode(
169        value=float_value_ast["value"],
170        location=_parse_location(float_value_ast["loc"]),
171    )
172
173
174def _parse_int_value(int_value_ast: dict, *_) -> "IntValueNode":
175    """
176    Creates and returns an IntValueNode instance from an int value's JSON AST
177    libgraphqlparser representation.
178    :param int_value_ast: int value's JSON AST libgraphqlparser representation
179    :type int_value_ast: dict
180    :param _: Ignored parameter
181    :return: an IntValueNode instance equivalent to the JSON AST representation
182    :rtype: IntValueNode
183    """
184    return IntValueNode(
185        value=int_value_ast["value"],
186        location=_parse_location(int_value_ast["loc"]),
187    )
188
189
190def _parse_values(
191    values_ast: Optional[List[dict]], validators: Validators, path: Path
192) -> List[
193    Union[
194        "BooleanValueNode",
195        "EnumValueNode",
196        "FloatValueNode",
197        "IntValueNode",
198        "ListValueNode",
199        "NullValueNode",
200        "ObjectValueNode",
201        "StringValueNode",
202        "VariableNode",
203    ]
204]:
205    """
206    Creates and returns a list of ValueNode instances from a list of value's
207    JSON AST libgraphqlparser representation.
208    :param values_ast: list of value's JSON AST libgraphqlparser representation
209    :type values_ast: Optional[List[dict]]
210    :param validators: the validators to use in order to validate this definition
211    :type validators: Validators
212    :param path: a Path object that contains the current field path
213    :type path: Path
214    :return: a list of ValueNode instances equivalent to the JSON AST
215    representation
216    :rtype: List[Union[BooleanValueNode, EnumValueNode, FloatValueNode, IntValueNode, ListValueNode, NullValueNode, ObjectValueNode, StringValueNode, VariableNode]]
217    """
218    if values_ast:
219        return [_parse_value(value, validators, path) for value in values_ast]
220    return []
221
222
223def _parse_list_value(
224    list_value_ast: dict, validators: Validators, path: Path
225) -> "ListValueNode":
226    """
227    Creates and returns a ListValueNode instance from a list value's JSON AST
228    libgraphqlparser representation.
229    :param list_value_ast: list value's JSON AST libgraphqlparser
230    representation
231    :type list_value_ast: dict
232    :param validators: the validators to use in order to validate this definition
233    :type validators: Validators
234    :param path: a Path object that contains the current field path
235    :type path: Path
236    :return: a ListValueNode instance equivalent to the JSON AST representation
237    :rtype: ListValueNode
238    """
239    return ListValueNode(
240        values=_parse_values(list_value_ast["values"], validators, path),
241        location=_parse_location(list_value_ast["loc"]),
242    )
243
244
245def _parse_null_value(null_value_ast: dict, *_) -> "NullValueNode":
246    """
247    Creates and returns a NullValueNode instance from a null value's JSON AST
248    libgraphqlparser representation.
249    :param null_value_ast: null value's JSON AST libgraphqlparser
250    representation
251    :type null_value_ast: dict
252    :param _: Ignored parameter
253    :return: a NullValueNode instance equivalent to the JSON AST representation
254    :rtype: NullValueNode
255    """
256    return NullValueNode(location=_parse_location(null_value_ast["loc"]))
257
258
259def _parse_object_field(
260    object_field_ast: dict, validators: Validators, path: Path
261) -> "ObjectFieldNode":
262    """
263    Creates and returns an ObjectFieldNode instance from an object field's JSON
264    AST libgraphqlparser representation.
265    :param object_field_ast: object field's JSON AST libgraphqlparser
266    representation
267    :type object_field_ast: dict
268    :param validators: the validators to use in order to validate this definition
269    :type validators: Validators
270    :param path: a Path object that contains the current field path
271    :type path: Path
272    :return: an ObjectFieldNode instance equivalent to the JSON AST
273    representation
274    :rtype: ObjectFieldNode
275    """
276    return ObjectFieldNode(
277        name=_parse_name(object_field_ast["name"]),
278        value=_parse_value(object_field_ast["value"], validators, path),
279        location=_parse_location(object_field_ast["loc"]),
280    )
281
282
283def _parse_object_fields(
284    object_fields_ast: Optional[List[dict]], validators: Validators, path: Path
285) -> List["ObjectFieldNode"]:
286    """
287    Creates and returns a list of ObjectFieldNode instances from a list of
288    object field's JSON AST libgraphqlparser representation.
289    :param object_fields_ast: list of object field's JSON AST libgraphqlparser
290    representation
291    :param validators: the validators to use in order to validate this definition
292    :type validators: Validators
293    :param path: a Path object that contains the current field path
294    :type path: Path
295    :type object_fields_ast: Optional[List[dict]]
296    :return: a list of ObjectFieldNode instances equivalent to the JSON AST
297    representation
298    :rtype: List[ObjectFieldNode]
299    """
300    if object_fields_ast:
301        object_fields = [
302            _parse_object_field(object_field, validators, path)
303            for object_field in object_fields_ast
304        ]
305
306        validators.validate(
307            "input-object-field-uniqueness",
308            input_fields=object_fields,
309            path=path,
310        )
311
312        return object_fields
313    return []
314
315
316def _parse_object_value(
317    object_value_ast: dict, validators: Validators, path: Path
318) -> "ObjectValueNode":
319    """
320    Creates and returns an ObjectValueNode instance from an object value's JSON
321    AST libgraphqlparser representation.
322    :param object_value_ast: object value's JSON AST libgraphqlparser
323    representation
324    :type object_value_ast: dict
325    :param validators: the validators to use in order to validate this definition
326    :type validators: Validators
327    :param path: a Path object that contains the current field path
328    :type path: Path
329    :return: an ObjectValueNode instance equivalent to the JSON AST
330    representation
331    :rtype: ObjectValueNode
332    """
333    return ObjectValueNode(
334        fields=_parse_object_fields(
335            object_value_ast["fields"], validators, path
336        ),
337        location=_parse_location(object_value_ast["loc"]),
338    )
339
340
341def _parse_string_value(string_value_ast: dict, *_) -> "StringValueNode":
342    """
343    Creates and returns a StringValueNode instance from a string value's JSON
344    AST libgraphqlparser representation.
345    :param string_value_ast: string value's JSON AST libgraphqlparser
346    representation
347    :type string_value_ast: dict
348    :param _: Ignored parameter
349    :return: a StringValueNode instance equivalent to the JSON AST
350    representation
351    :rtype: StringValueNode
352    """
353    return StringValueNode(
354        value=string_value_ast["value"],
355        location=_parse_location(string_value_ast["loc"]),
356    )
357
358
359_VALUE_PARSER_MAPPING = {
360    "BooleanValue": _parse_boolean_value,
361    "EnumValue": _parse_enum_value,
362    "FloatValue": _parse_float_value,
363    "IntValue": _parse_int_value,
364    "ListValue": _parse_list_value,
365    "NullValue": _parse_null_value,
366    "ObjectValue": _parse_object_value,
367    "StringValue": _parse_string_value,
368    "Variable": _parse_variable,
369}
370
371
372def _parse_value(
373    value_ast: Optional[dict], validators: Validators, path: Path
374) -> Optional[
375    Union[
376        "BooleanValueNode",
377        "EnumValueNode",
378        "FloatValueNode",
379        "IntValueNode",
380        "ListValueNode",
381        "NullValueNode",
382        "ObjectValueNode",
383        "StringValueNode",
384        "VariableNode",
385    ]
386]:
387    """
388    Creates and returns a ValueNode instance from a value's JSON AST
389    libgraphqlparser representation.
390    :param value_ast: value's JSON AST libgraphqlparser representation
391    :type value_ast: Optional[dict]
392    :param validators: the validators to use in order to validate this definition
393    :type validators: Validators
394    :param path: a Path object that contains the current field path
395    :type path: Path
396    :return: a ValueNode instance equivalent to the JSON AST representation
397    :rtype: Optional[Union[BooleanValueNode, EnumValueNode, FloatValueNode, IntValueNode, ListValueNode, NullValueNode, ObjectValueNode, StringValueNode, VariableNode]]
398    """
399    if value_ast:
400        return _VALUE_PARSER_MAPPING[value_ast["kind"]](
401            value_ast, validators, path
402        )
403    return None
404
405
406def _parse_argument(
407    argument_ast: dict, validators: Validators, path: Path
408) -> "ArgumentNode":
409    """
410    Creates and returns an ArgumentNode instance from an argument's JSON AST
411    libgraphqlparser representation.
412    :param argument_ast: argument's JSON AST libgraphqlparser representation
413    :type argument_ast: dict
414    :param validators: the validators to use in order to validate this definition
415    :type validators: Validators
416    :param path: a Path object that contains the current field path
417    :type path: Path
418    :return: an ArgumentNode instance equivalent to the JSON AST representation
419    :rtype: ArgumentNode
420    """
421    arg = ArgumentNode(
422        name=_parse_name(argument_ast["name"]),
423        value=_parse_value(argument_ast["value"], validators, path),
424        location=_parse_location(argument_ast["loc"]),
425    )
426
427    if isinstance(arg.value, VariableNode):
428        loca = (
429            validators.ctx["current_directive_name"]
430            if validators.ctx.get("in_directive", False)
431            else validators.ctx["current_field_name"]
432        )
433
434        if validators.ctx["in_operation"]:
435            validators.ctx["per_operation"][
436                validators.ctx["current_operation_name"]
437            ].setdefault("args_using_var", []).append(
438                {
439                    "arg": arg,
440                    "node_location": loca,
441                    "is_directive": validators.ctx.get("in_directive", False),
442                    "path": path,
443                }
444            )
445        else:
446            validators.ctx["per_fragment"][
447                validators.ctx["current_fragment_name"]
448            ].setdefault("args_using_var", []).append(
449                {
450                    "arg": arg,
451                    "node_location": loca,
452                    "is_directive": validators.ctx.get("in_directive", False),
453                    "path": path,
454                }
455            )
456
457    return arg
458
459
460def _parse_arguments(
461    arguments_ast: Optional[List[dict]], validators: "Validators", path: "Path"
462) -> List["ArgumentNode"]:
463    """
464    Creates and returns a list of ArgumentNode instances from a list of
465    argument's JSON AST libgraphqlparser representation.
466    :param arguments_ast: list of argument's JSON AST libgraphqlparser
467    representation
468    :type arguments_ast: Optional[List[dict]]
469    :param validators: the Validators object that will be used to validate these arguments
470    :param path: a Path object that contains the current field path
471    :type validators: Validators
472    :type path: Path
473    :return: a list of ArgumentNode instances equivalent to the JSON AST
474    representation
475    :rtype: List[ArgumentNode]
476    """
477    if arguments_ast:
478        arguments = [
479            _parse_argument(argument, validators, path)
480            for argument in arguments_ast
481        ]
482        validators.validate(
483            rule="argument-uniqueness", arguments=arguments, path=path
484        )
485        return arguments
486    return []
487
488
489def _parse_directive(
490    directive_ast: dict, validators: "Validators", path: "Path"
491) -> "DirectiveNode":
492    """
493    Creates and returns a DirectiveNode instance from a directive's JSON AST
494    libgraphqlparser representation.
495    :param directive_ast: directive's JSON AST libgraphqlparser representation
496    :type directive_ast: dict
497    :param validators: the Validators object that will be used to validate these arguments
498    :param path: a Path object that contains the current field path
499    :type validators: Validators
500    :type path: Path
501    :return: a DirectiveNode instance equivalent to the JSON AST representation
502    :rtype: DirectiveNode
503    """
504    name = _parse_name(directive_ast["name"])
505    validators.ctx["in_directive"] = True
506    validators.ctx["current_directive_name"] = name.value
507
508    directive = DirectiveNode(
509        name=name,
510        arguments=_parse_arguments(
511            directive_ast["arguments"], validators, path
512        ),
513        location=_parse_location(directive_ast["loc"]),
514    )
515
516    validators.ctx["in_directive"] = False
517
518    validators.validate(
519        rule="values-of-correct-type", node=directive, path=path
520    )
521
522    validators.validate(rule="argument-names", node=directive, path=path)
523
524    validators.validate(rule="required-arguments", node=directive, path=path)
525
526    validators.validate(
527        rule="directives-are-defined", directive=directive, path=path
528    )
529
530    return directive
531
532
533def _parse_directives(
534    directives_ast: Optional[List[dict]],
535    validators: "Validators",
536    path: "Path",
537) -> List["DirectiveNode"]:
538    """
539    Creates and returns a list of DirectiveNode instances from a list of
540    directive's JSON AST libgraphqlparser representation.
541    :param directives_ast: list of directive's JSON AST libgraphqlparser
542    representation
543    :type directives_ast: Optional[List[dict]]
544    :param validators: the Validators object that will be used to validate these arguments
545    :param path: a Path object that contains the current field path
546    :type validators: Validators
547    :type path: Path
548    :return: a list of DirectiveNode instances equivalent to the JSON AST
549    representation
550    :rtype: List[DirectiveNode]
551    """
552    if directives_ast:
553        directives = [
554            _parse_directive(directive, validators, path)
555            for directive in directives_ast
556        ]
557
558        validators.validate(
559            rule="directives-are-unique-per-location",
560            directives=directives,
561            path=path,
562        )
563
564        return directives
565    return []
566
567
568def _parse_field(
569    field_ast: dict, validators: "Validators", path: "Path"
570) -> "FieldNode":
571    """
572    Creates and returns a FieldNode instance from a field's JSON AST
573    libgraphqlparser representation.
574    :param field_ast: field's JSON AST libgraphqlparser representation
575    :type field_ast: dict
576    :param validators: the Validators object that will be used to validate these arguments
577    :param path: a Path object that contains the current field path
578    :type validators: Validators
579    :type path: Path
580    :return: a FieldNode instance equivalent to the JSON AST representation
581    :rtype: FieldNode
582    """
583
584    name = _parse_name(field_ast["name"])
585    path = Path(prev=path, key=name.value)
586    parent_type_name = validators.ctx["parent_type_name"]
587
588    validators.ctx["parent_type_name"] = get_schema_field_type_name(
589        parent_type_name, name.value, validators.schema
590    )
591
592    validators.ctx["in_directive"] = False
593    validators.ctx["current_field_name"] = f"{parent_type_name}.{name}"
594
595    field = FieldNode(
596        alias=_parse_name(field_ast["alias"]) if field_ast["alias"] else None,
597        name=name,
598        arguments=_parse_arguments(field_ast["arguments"], validators, path),
599        directives=_parse_directives(
600            field_ast["directives"], validators, path
601        ),
602        selection_set=_parse_selection_set(
603            field_ast["selectionSet"], validators, path
604        ),
605        location=_parse_location(field_ast["loc"]),
606    )
607
608    validators.ctx["parent_type_name"] = parent_type_name
609
610    validators.validate(
611        rule="directives-are-in-valid-locations", node=field, path=path
612    )
613
614    validators.validate(
615        rule="field-selections-on-objects-interfaces-and-unions-types",
616        field=field,
617        path=path,
618    )
619
620    validators.validate(rule="leaf-field-selections", field=field, path=path)
621
622    validators.validate(rule="values-of-correct-type", node=field, path=path)
623
624    validators.validate(rule="argument-names", node=field, path=path)
625
626    validators.validate(rule="required-arguments", node=field, path=path)
627
628    return field
629
630
631def _parse_fragment_spread(
632    fragment_spread_ast: dict, validators: "Validators", path: "Path"
633) -> "FragmentSpreadNode":
634    """
635    Creates and returns a FragmentSpreadNode instance from a fragment spread's
636    JSON AST libgraphqlparser representation.
637    :param fragment_spread_ast: fragment spread's JSON AST libgraphqlparser
638    representation
639    :type fragment_spread_ast: dict
640    :param validators: the Validators object that will be used to validate these arguments
641    :param path: a Path object that contains the current field path
642    :type validators: Validators
643    :type path: Path
644    :return: a FragmentSpreadNode instance equivalent to the JSON AST
645    representation
646    :rtype: FragmentSpreadNode
647    """
648    fragment_spead = FragmentSpreadNode(
649        name=_parse_name(fragment_spread_ast["name"]),
650        directives=_parse_directives(
651            fragment_spread_ast["directives"], validators, path
652        ),
653        location=_parse_location(fragment_spread_ast["loc"]),
654    )
655
656    validators.validate(
657        rule="directives-are-in-valid-locations",
658        node=fragment_spead,
659        path=path,
660    )
661
662    validators.ctx.setdefault("fragment_spreads", []).append(fragment_spead)
663    validators.ctx.setdefault("spreaded_in", {}).setdefault(
664        validators.ctx["parent_type_name"], []
665    ).append({"spread": fragment_spead, "path": path})
666
667    if validators.ctx["in_operation"]:
668        validators.ctx["per_operation"][
669            validators.ctx["current_operation_name"]
670        ].setdefault("spreads", []).append(fragment_spead)
671    else:
672        validators.ctx["per_fragment"][
673            validators.ctx["current_fragment_name"]
674        ].setdefault("spreads", []).append(fragment_spead)
675
676    return fragment_spead
677
678
679def _parse_inline_fragment(
680    inline_fragment_ast: dict, validators: "Validators", path: "Path"
681) -> "InlineFragmentNode":
682    """
683    Creates and returns an InlineFragmentNode instance from an inline spread's
684    JSON AST libgraphqlparser representation.
685    :param inline_fragment_ast: inline spread's JSON AST libgraphqlparser
686    representation
687    :type inline_fragment_ast: dict
688    :param validators: the Validators object that will be used to validate these arguments
689    :param path: a Path object that contains the current field path
690    :type validators: Validators
691    :type path: Path
692    :return: an InlineFragmentNode instance equivalent to the JSON AST
693    representation
694    :rtype: InlineFragmentNode
695    """
696
697    parent_type_name = validators.ctx["parent_type_name"]
698
699    type_cond = (
700        _parse_named_type(inline_fragment_ast["typeCondition"])
701        if inline_fragment_ast["typeCondition"]
702        else None
703    )
704    if type_cond:
705        validators.ctx["parent_type_name"] = type_cond.name.value
706
707    inline_frag = InlineFragmentNode(
708        directives=_parse_directives(
709            inline_fragment_ast["directives"], validators, path
710        ),
711        type_condition=type_cond,
712        selection_set=_parse_selection_set(
713            inline_fragment_ast["selectionSet"], validators, path
714        ),
715        location=_parse_location(inline_fragment_ast["loc"]),
716    )
717
718    validators.validate(
719        rule="directives-are-in-valid-locations", node=inline_frag, path=path
720    )
721
722    validators.validate(
723        rule="fragment-spread-type-existence", fragment=inline_frag, path=path
724    )
725    validators.validate(
726        rule="fragments-on-composite-types", fragment=inline_frag, path=path
727    )
728
729    validators.ctx.setdefault("inlined_in", {}).setdefault(
730        validators.ctx["parent_type_name"], []
731    ).append(inline_frag)
732    validators.ctx["parent_type_name"] = parent_type_name
733
734    return inline_frag
735
736
737_SELECTION_PARSER_MAPPING = {
738    "Field": _parse_field,
739    "FragmentSpread": _parse_fragment_spread,
740    "InlineFragment": _parse_inline_fragment,
741}
742
743
744def _parse_selection(
745    selection_ast: dict, validators: "Validators", path: "Path"
746) -> Union["FieldNode", "FragmentSpreadNode", "InlineFragmentNode"]:
747    """
748    Creates and returns a SelectionNode instance from a selection's JSON AST
749    libgraphqlparser representation.
750    :param selection_ast: selection's JSON AST libgraphqlparser representation
751    :type selection_ast: dict
752    :param validators: the Validators object that will be used to validate these arguments
753    :param path: a Path object that contains the current field path
754    :type validators: Validators
755    :type path: Path
756    :return: a SelectionNode instance equivalent to the JSON AST representation
757    :rtype: Union[FieldNode, FragmentSpreadNode, InlineFragmentNode]
758    """
759    return _SELECTION_PARSER_MAPPING[selection_ast["kind"]](
760        selection_ast, validators, path
761    )
762
763
764def _parse_selections(
765    selections_ast: Optional[List[dict]], validators: Validators, path: Path
766) -> List[Union["FieldNode", "FragmentSpreadNode", "InlineFragmentNode"]]:
767    """
768    Creates and returns a list of SelectionNode instances from a list of
769    selection's JSON AST libgraphqlparser representation.
770    :param selections_ast: list of selection's JSON AST libgraphqlparser
771    representation
772    :type selections_ast: Optional[List[dict]]
773    :param validators: the Validators object that will be used to validate these arguments
774    :param path: a Path object that contains the current field path
775    :type validators: Validators
776    :type path: Path
777    :return: a list of SelectionNode instances equivalent to the JSON AST
778    representation
779    :rtype: List[Union[FieldNode, FragmentSpreadNode, InlineFragmentNode]]
780    """
781
782    if selections_ast:
783        return [
784            _parse_selection(selection, validators, path)
785            for selection in selections_ast
786        ]
787    return []
788
789
790def _parse_selection_set(
791    selection_set_ast: Optional[dict], validators: Validators, path: Path
792) -> Optional["SelectionSetNode"]:
793    """
794    Creates and returns a SelectionSetNode instance from a selection set's JSON
795    AST libgraphqlparser representation.
796    :param selection_set_ast: selection set's JSON AST libgraphqlparser
797    representation
798    :type selection_set_ast: Optional[dict]
799    :param validators: the Validators object that will be used to validate these arguments
800    :param path: a Path object that contains the current field path
801    :type validators: Validators
802    :type path: Path
803    :return: a SelectionSetNode instance equivalent to the JSON AST
804    representation
805    :rtype: Optional[SelectionSetNode]
806    """
807    if selection_set_ast:
808        return SelectionSetNode(
809            selections=_parse_selections(
810                selection_set_ast["selections"], validators, path
811            ),
812            location=_parse_location(selection_set_ast["loc"]),
813        )
814    return None
815
816
817def _parse_fragment_definition(
818    fragment_definition_ast: dict, validators: "Validators", path: Path
819) -> "FragmentDefinitionNode":
820    """
821    Creates and returns a FragmentDefinitionNode instance from a fragment
822    definition's JSON AST libgraphqlparser representation.
823    :param fragment_definition_ast: fragment definition's JSON AST
824    libgraphqlparser representation
825    :type fragment_definition_ast: dict
826    :param validators: the Validators object that will be used to validate these arguments
827    :param path: a Path object that contains the current field path
828    :type validators: Validators
829    :type path: Path
830    :return: a FragmentDefinitionNode instance equivalent to the JSON AST
831    representation
832    :rtype: FragmentDefinitionNode
833    """
834
835    parent_type_name = validators.ctx.get("parent_type_name")
836    name = _parse_name(fragment_definition_ast["name"])
837    type_cond = _parse_named_type(fragment_definition_ast["typeCondition"])
838    validators.ctx["parent_type_name"] = type_cond.name.value
839    validators.ctx["in_operation"] = False
840    validators.ctx["current_fragment_name"] = name.value
841    validators.ctx.setdefault("per_fragment", {}).setdefault(name.value, {})
842
843    fragment = FragmentDefinitionNode(
844        name=name,
845        type_condition=type_cond,
846        directives=_parse_directives(
847            fragment_definition_ast["directives"], validators, path
848        ),
849        selection_set=_parse_selection_set(
850            fragment_definition_ast["selectionSet"], validators, path
851        ),
852        location=_parse_location(fragment_definition_ast["loc"]),
853    )
854
855    validators.validate(
856        rule="directives-are-in-valid-locations", node=fragment, path=path
857    )
858
859    validators.validate(
860        rule="fragment-spread-type-existence", fragment=fragment, path=path
861    )
862    validators.validate(
863        rule="fragments-on-composite-types", fragment=fragment, path=path
864    )
865
866    validators.ctx["parent_type_name"] = parent_type_name
867
868    return fragment
869
870
871def _parse_type(
872    type_ast: dict,
873) -> Union["ListTypeNode", "NonNullTypeNode", "NamedTypeNode"]:
874    """
875    Creates and returns a TypeNode from a type's JSON AST libgraphqlparser
876    representation.
877    :param type_ast: type's JSON AST libgraphqlparser representation
878    :type type_ast: dict
879    :return: a TypeNode instance equivalent to the JSON AST representation
880    :rtype: Union[ListTypeNode, NonNullTypeNode, NamedTypeNode]
881    """
882    if type_ast["kind"] == "ListType":
883        return ListTypeNode(
884            type=_parse_type(type_ast["type"]),
885            location=_parse_location(type_ast["loc"]),
886        )
887    if type_ast["kind"] == "NonNullType":
888        return NonNullTypeNode(
889            type=_parse_type(type_ast["type"]),
890            location=_parse_location(type_ast["loc"]),
891        )
892    return _parse_named_type(type_ast)
893
894
895def _parse_variable_definition(
896    variable_definition_ast: dict, validators: Validators, path: Path
897) -> "VariableDefinitionNode":
898    """
899    Creates and returns a VariableDefinitionNode instance from a variable
900    definition's JSON AST libgraphqlparser representation.
901    :param variable_definition_ast: variable definition's JSON AST
902    libgraphqlparser representation
903    :type variable_definition_ast: dict
904    :param validators: the Validators object that will be used to validate these arguments
905    :param path: a Path object that contains the current field path
906    :type validators: Validators
907    :type path: Path
908    :return: a VariableDefinitionNode instance equivalent to the JSON AST
909    representation
910    :rtype: VariableDefinitionNode
911    """
912    variable = VariableDefinitionNode(
913        variable=_parse_variable(
914            variable_definition_ast["variable"], validators
915        ),
916        type=_parse_type(variable_definition_ast["type"]),
917        default_value=_parse_value(
918            variable_definition_ast["defaultValue"], validators, path
919        ),
920        location=_parse_location(variable_definition_ast["loc"]),
921    )
922
923    validators.validate(
924        rule="variables-are-input-types", variable=variable, path=path
925    )
926
927    return variable
928
929
930def _parse_variable_definitions(
931    variable_definitions_ast: Optional[List[dict]],
932    validators: Validators,
933    path: Path,
934) -> List["VariableDefinitionNode"]:
935    """
936    Creates and returns a list of VariableDefinitionNode instances from a list
937    of variable definition's JSON AST libgraphqlparser representation.
938    :param variable_definitions_ast: list of variable definition's JSON AST
939    libgraphqlparser representation
940    :type variable_definitions_ast: Optional[List[dict]]
941    :param validators: the Validators object that will be used to validate these arguments
942    :param path: a Path object that contains the current field path
943    :type validators: Validators
944    :type path: Path
945    :return: a list of VariableDefinitionNode instances equivalent to the JSON
946    AST representation
947    :rtype: List[VariableDefinitionNode]
948    """
949    if variable_definitions_ast:
950        validators.ctx["in_variable_definitions"] = True
951        variables = [
952            _parse_variable_definition(variable_definition, validators, path)
953            for variable_definition in variable_definitions_ast
954        ]
955        validators.ctx["in_variable_definitions"] = False
956
957        validators.validate(
958            rule="variable-uniqueness",
959            variable_definitions=variables,
960            path=path,
961        )
962
963        return variables
964    return []
965
966
967def _get_operation_type_name(operation_type, schema):
968    return getattr(schema, f"{operation_type.lower()}_operation_name")
969
970
971def _parse_operation_definition(
972    operation_definition_ast: dict, validators: "Validators", path: Path
973) -> "OperationDefinitionNode":
974    """
975    Creates and returns an OperationDefinitionNode instance from an operation
976    definition's JSON AST libgraphqlparser representation.
977    :param operation_definition_ast: operation definition's JSON AST
978    libgraphqlparser representation
979    :type operation_definition_ast: dict
980    :param validators: the Validators object that will be used to validate these arguments
981    :param path: a Path object that contains the current field path
982    :type validators: Validators
983    :type path: Path
984    :return: an OperationDefinitionNode instance equivalent to the JSON AST
985    representation
986    :rtype: OperationDefinitionNode
987    """
988    operation_type = operation_definition_ast["operation"]
989    name = (
990        _parse_name(operation_definition_ast["name"])
991        if operation_definition_ast["name"]
992        else None
993    )
994
995    validators.ctx["parent_type_name"] = _get_operation_type_name(
996        operation_type, validators.schema
997    )
998    validators.ctx["in_operation"] = True
999    validators.ctx["current_operation_name"] = name.value if name else "None"
1000    validators.ctx.setdefault("per_operation", {}).setdefault(
1001        name.value if name else "None", {}
1002    )
1003
1004    operation = OperationDefinitionNode(
1005        operation_type=operation_type,
1006        name=name,
1007        variable_definitions=_parse_variable_definitions(
1008            operation_definition_ast["variableDefinitions"], validators, path
1009        ),
1010        directives=_parse_directives(
1011            operation_definition_ast["directives"], validators, path
1012        ),
1013        selection_set=_parse_selection_set(
1014            operation_definition_ast["selectionSet"], validators, path
1015        ),
1016        location=_parse_location(operation_definition_ast["loc"]),
1017    )
1018
1019    validators.validate(
1020        rule="directives-are-in-valid-locations", node=operation, path=path
1021    )
1022
1023    return operation
1024
1025
1026_DEFINITION_PARSER_MAPPING = {
1027    "FragmentDefinition": _parse_fragment_definition,
1028    "OperationDefinition": _parse_operation_definition,
1029}
1030
1031
1032def _parse_definition(
1033    definition_ast: dict, validators: "Validators", path: Path
1034) -> Union["FragmentDefinitionNode", "OperationDefinitionNode"]:
1035    """
1036    Creates and returns a DefinitionNode instance from a definition's JSON AST
1037    libgraphqlparser representation.
1038    :param definition_ast: definition's JSON AST libgraphqlparser
1039    representation
1040    :type definition_ast: dict
1041    :param validators: the Validators object that will be used to validate these arguments
1042    :param path: a Path object that contains the current field path
1043    :type validators: Validators
1044    :type path: Path
1045    :return: a DefinitionNode instance equivalent to the JSON AST
1046    representation
1047    :rtype: Union[FragmentDefinitionNode, OperationDefinitionNode]
1048    """
1049    return _DEFINITION_PARSER_MAPPING[definition_ast["kind"]](
1050        definition_ast, validators, path
1051    )
1052
1053
1054def _parse_definitions(
1055    definitions_ast: Optional[List[dict]],
1056    validators: Validators,
1057    path: Path = None,
1058) -> List[Union["FragmentDefinitionNode", "OperationDefinitionNode"]]:
1059    """
1060    Creates and returns a list of DefinitionNode instances from a list of
1061    definition's JSON AST libgraphqlparser representation.
1062    :param definitions_ast: list of definition's JSON AST libgraphqlparser
1063    representation
1064    :type definitions_ast: Optional[List[dict]]
1065    :param validators: the Validators object that will be used to validate these arguments
1066    :param path: a Path object that contains the current field path
1067    :type validators: Validators
1068    :type path: Path
1069    :return: a list of DefinitionNode instances equivalent to the JSON AST
1070    representation
1071    :rtype: List[Union[FragmentDefinitionNode, OperationDefinitionNode]]
1072    """
1073
1074    parsed_def = {"FragmentDefinition": [], "OperationDefinition": []}
1075
1076    if definitions_ast:
1077        for definition in definitions_ast:
1078            parsed_def[definition["kind"]].append(
1079                _parse_definition(definition, validators, path)
1080            )
1081
1082    validators.validate(
1083        rule="fragment-spreads-must-not-form-cycles",
1084        fragments=parsed_def["FragmentDefinition"],
1085        path=None,
1086    )
1087
1088    validators.validate(
1089        rule="operation-name-uniqueness",
1090        operations=parsed_def["OperationDefinition"],
1091        path=path,
1092    )
1093    validators.validate(
1094        rule="lone-anonymous-operation",
1095        operations=parsed_def["OperationDefinition"],
1096        path=path,
1097    )
1098
1099    validators.validate(
1100        rule="single-root-field", definitions=parsed_def, path=path
1101    )
1102
1103    validators.validate(
1104        rule="fragment-name-uniqueness",
1105        fragments=parsed_def["FragmentDefinition"],
1106        path=path,
1107    )
1108
1109    validators.validate(
1110        rule="fragment-spread-target-defined",
1111        fragments=parsed_def["FragmentDefinition"],
1112        path=path,
1113    )
1114
1115    validators.validate(
1116        rule="fragment-must-be-used",
1117        fragments=parsed_def["FragmentDefinition"],
1118        path=path,
1119    )
1120
1121    validators.validate(
1122        rule="fragment-spread-is-possible",
1123        fragments=parsed_def["FragmentDefinition"],
1124        path=path,
1125    )
1126
1127    validators.validate(
1128        rule="all-variable-uses-defined",
1129        operations=parsed_def["OperationDefinition"],
1130        path=path,
1131    )
1132
1133    validators.validate(
1134        rule="all-variables-used",
1135        operations=parsed_def["OperationDefinition"],
1136        path=path,
1137    )
1138
1139    validators.validate(
1140        rule="all-variable-usages-are-allowed",
1141        operations=parsed_def["OperationDefinition"],
1142        path=path,
1143    )
1144
1145    return parsed_def["FragmentDefinition"] + parsed_def["OperationDefinition"]
1146
1147
1148def document_from_ast_json(
1149    document_ast: dict, query: Union[str, bytes], schema: "GraphQLSchema"
1150) -> "DocumentNode":
1151    """
1152    Creates and returns a DocumentNode instance from a document's JSON AST
1153    libgraphqlparser representation.
1154    :param document_ast: document's JSON AST libgraphqlparser representation
1155    :param query: query to parse and transform into a DocumentNode
1156    :param schema: the GraphQLSchema instance linked to the engine
1157    :type document_ast: dict
1158    :type query: Union[str, bytes]
1159    :type schema: GraphQLSchema
1160    :return: a DocumentNode instance equivalent to the JSON AST representation
1161    :rtype: DocumentNode
1162
1163    :Example:
1164
1165    >>> from tartiflette.language.parsers.libgraphqlparser.transformers import (
1166    >>>     document_from_ast_json
1167    >>> )
1168    >>>
1169    >>>
1170    >>> document = document_from_ast_json({
1171    >>>     "kind": "Document",
1172    >>>     "loc": {
1173    >>>         "start": {"line": 2, "column": 13},
1174    >>>         "end": {"line": 4, "column": 14},
1175    >>>     },
1176    >>>     "definitions": [
1177    >>>         {
1178    >>>             "kind": "OperationDefinition",
1179    >>>             "loc": {
1180    >>>                 "start": {"line": 2, "column": 13},
1181    >>>                 "end": {"line": 4, "column": 14},
1182    >>>             },
1183    >>>             "operation": "query",
1184    >>>             "name": None,
1185    >>>             "variableDefinitions": None,
1186    >>>             "directives": None,
1187    >>>             "selectionSet": {
1188    >>>                 "kind": "SelectionSet",
1189    >>>                 "loc": {
1190    >>>                     "start": {"line": 2, "column": 13},
1191    >>>                     "end": {"line": 4, "column": 14},
1192    >>>                 },
1193    >>>                 "selections": [
1194    >>>                     {
1195    >>>                         "kind": "Field",
1196    >>>                         "loc": {
1197    >>>                             "start": {"line": 3, "column": 15},
1198    >>>                             "end": {"line": 3, "column": 20},
1199    >>>                         },
1200    >>>                         "alias": None,
1201    >>>                         "name": {
1202    >>>                             "kind": "Name",
1203    >>>                             "loc": {
1204    >>>                                 "start": {"line": 3, "column": 15},
1205    >>>                                 "end": {"line": 3, "column": 20},
1206    >>>                             },
1207    >>>                             "value": "hello",
1208    >>>                         },
1209    >>>                         "arguments": None,
1210    >>>                         "directives": None,
1211    >>>                         "selectionSet": None,
1212    >>>                     }
1213    >>>                 ],
1214    >>>             },
1215    >>>         }
1216    >>>     ],
1217    >>> },
1218    >>> '''
1219    >>> {
1220    >>>   hello
1221    >>> }
1222    >>> ''')
1223    """
1224
1225    validators = Validators(schema, RULE_SET)
1226
1227    definitions = _parse_definitions(document_ast["definitions"], validators)
1228
1229    validators.validate(
1230        rule="executable-definitions", definitions=definitions, path=None
1231    )
1232
1233    return DocumentNode(
1234        definitions=definitions,
1235        validators=validators,
1236        hash_id=hash(query),
1237        location=_parse_location(document_ast["loc"]),
1238    )
1239