apollo_smith/
scalar.rs

1use crate::description::Description;
2use crate::directive::Directive;
3use crate::directive::DirectiveLocation;
4use crate::name::Name;
5use crate::DocumentBuilder;
6use apollo_compiler::ast;
7use arbitrary::Result as ArbitraryResult;
8use indexmap::IndexMap;
9
10/// Represents scalar types such as Int, String, and Boolean.
11/// Scalars cannot have fields.
12///
13/// *ScalarTypeDefinition*:
14///     Description? **scalar** Name Directives?
15///
16/// Detailed documentation can be found in [GraphQL spec](https://spec.graphql.org/October2021/#sec-Scalar).
17#[derive(Debug, Clone)]
18pub struct ScalarTypeDef {
19    pub(crate) name: Name,
20    pub(crate) description: Option<Description>,
21    pub(crate) directives: IndexMap<Name, Directive>,
22    pub(crate) extend: bool,
23}
24
25impl From<ScalarTypeDef> for ast::Definition {
26    fn from(x: ScalarTypeDef) -> Self {
27        if x.extend {
28            ast::ScalarTypeExtension {
29                name: x.name.into(),
30                directives: Directive::to_ast(x.directives),
31            }
32            .into()
33        } else {
34            ast::ScalarTypeDefinition {
35                description: x.description.map(Into::into),
36                name: x.name.into(),
37                directives: Directive::to_ast(x.directives),
38            }
39            .into()
40        }
41    }
42}
43
44impl TryFrom<apollo_parser::cst::ScalarTypeDefinition> for ScalarTypeDef {
45    type Error = crate::FromError;
46
47    fn try_from(scalar_def: apollo_parser::cst::ScalarTypeDefinition) -> Result<Self, Self::Error> {
48        Ok(Self {
49            description: scalar_def
50                .description()
51                .and_then(|d| d.string_value())
52                .map(|s| Description::from(Into::<String>::into(s))),
53            name: scalar_def.name().unwrap().into(),
54            directives: scalar_def
55                .directives()
56                .map(Directive::convert_directives)
57                .transpose()?
58                .unwrap_or_default(),
59            extend: false,
60        })
61    }
62}
63
64impl TryFrom<apollo_parser::cst::ScalarTypeExtension> for ScalarTypeDef {
65    type Error = crate::FromError;
66
67    fn try_from(scalar_def: apollo_parser::cst::ScalarTypeExtension) -> Result<Self, Self::Error> {
68        Ok(Self {
69            description: None,
70            name: scalar_def.name().unwrap().into(),
71            directives: scalar_def
72                .directives()
73                .map(Directive::convert_directives)
74                .transpose()?
75                .unwrap_or_default(),
76            extend: true,
77        })
78    }
79}
80
81impl DocumentBuilder<'_> {
82    /// Create an arbitrary `ScalarTypeDef`
83    pub fn scalar_type_definition(&mut self) -> ArbitraryResult<ScalarTypeDef> {
84        let extend = !self.scalar_type_defs.is_empty() && self.u.arbitrary().unwrap_or(false);
85        let name = if extend {
86            let available_scalars: Vec<&Name> = self
87                .scalar_type_defs
88                .iter()
89                .filter_map(|scalar| {
90                    if scalar.extend {
91                        None
92                    } else {
93                        Some(&scalar.name)
94                    }
95                })
96                .collect();
97            (*self.u.choose(&available_scalars)?).clone()
98        } else {
99            self.type_name()?
100        };
101        let description = self
102            .u
103            .arbitrary()
104            .unwrap_or(false)
105            .then(|| self.description())
106            .transpose()?;
107        let directives = self.directives(DirectiveLocation::Scalar)?;
108        // Extended scalar must have directive
109        let extend = !directives.is_empty() && self.u.arbitrary().unwrap_or(false);
110
111        Ok(ScalarTypeDef {
112            name,
113            description,
114            directives,
115            extend,
116        })
117    }
118}