1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
use bluejay_core::definition::{DirectiveDefinition, DirectiveLocation, SchemaDefinition};
use bluejay_core::executable::ExecutableDocument;
use bluejay_core::AsIter;
#[cfg(feature = "parser-integration")]
use bluejay_parser::{
    ast::executable::ExecutableDocument as ParserExecutableDocument,
    error::{Annotation, Error as ParserError},
    HasSpan,
};
use itertools::Itertools;

pub enum DirectiveError<'a, const CONST: bool, E: ExecutableDocument, S: SchemaDefinition> {
    DirectiveDoesNotExist {
        directive: &'a E::Directive<CONST>,
    },
    DirectiveInInvalidLocation {
        directive: &'a E::Directive<CONST>,
        directive_definition: &'a S::DirectiveDefinition,
        location: DirectiveLocation,
    },
    DirectivesNotUniquePerLocation {
        directives: Vec<&'a E::Directive<CONST>>,
        directive_definition: &'a S::DirectiveDefinition,
    },
}

#[cfg(feature = "parser-integration")]
impl<'a, const CONST: bool, S: SchemaDefinition>
    From<DirectiveError<'a, CONST, ParserExecutableDocument<'a>, S>> for ParserError
{
    fn from(value: DirectiveError<'a, CONST, ParserExecutableDocument<'a>, S>) -> Self {
        match value {
            DirectiveError::DirectiveDoesNotExist { directive } => Self::new(
                format!(
                    "No directive definition with name `@{}`",
                    directive.name().as_ref()
                ),
                Some(Annotation::new(
                    "No directive definition with this name",
                    directive.name().span().clone(),
                )),
                Vec::new(),
            ),
            DirectiveError::DirectiveInInvalidLocation {
                directive,
                directive_definition,
                location,
            } => Self::new(
                format!(
                    "Directive @{} cannot be used at location {location}. It is only allowed at the following locations: {}",
                    directive.name().as_ref(),
                    directive_definition.locations().iter().join(", "),
                ),
                Some(Annotation::new(
                    format!("Cannot be used at location {location}"),
                    directive.span().clone(),
                )),
                Vec::new(),
            ),
            DirectiveError::DirectivesNotUniquePerLocation { directives, directive_definition } => Self::new(
                format!(
                    "Directive @{} is not repeatable but was used multiple times in the same location",
                    directive_definition.name(),
                ),
                None,
                directives.into_iter().map(|directive| Annotation::new(
                    "Usage of directive",
                    directive.span().clone(),
                )).collect(),
            ),
        }
    }
}