/rust/registry/src/index.crates.io-1949cf8c6b5b557f/async-graphql-parser-7.0.17/src/lib.rs
Line | Count | Source |
1 | | //! A parser for GraphQL. Used in the [`async-graphql`](https://crates.io/crates/async-graphql) |
2 | | //! crate. |
3 | | //! |
4 | | //! It uses the [pest](https://crates.io/crates/pest) crate to parse the input and then transforms |
5 | | //! it into Rust types. |
6 | | #![warn(missing_docs)] |
7 | | #![allow(clippy::unnecessary_wraps)] |
8 | | #![allow(clippy::upper_case_acronyms)] |
9 | | #![allow(clippy::needless_question_mark)] |
10 | | #![allow(clippy::uninlined_format_args)] |
11 | | #![forbid(unsafe_code)] |
12 | | |
13 | | use std::fmt::{self, Display, Formatter}; |
14 | | |
15 | | use async_graphql_value::Name; |
16 | | pub use parse::{parse_query, parse_schema}; |
17 | | use pest::{RuleType, error::LineColLocation}; |
18 | | pub use pos::{Pos, Positioned}; |
19 | | use serde::{Serialize, Serializer}; |
20 | | |
21 | | use crate::types::OperationType; |
22 | | |
23 | | pub mod types; |
24 | | |
25 | | mod parse; |
26 | | mod pos; |
27 | | |
28 | | /// Parser error. |
29 | | #[derive(Debug, Clone, PartialEq, Eq)] |
30 | | #[non_exhaustive] |
31 | | pub enum Error { |
32 | | /// A syntax error occurred. |
33 | | Syntax { |
34 | | /// The message of the error, nicely formatted with newlines. |
35 | | message: String, |
36 | | /// The start position of the error. |
37 | | start: Pos, |
38 | | /// The end position of the error, if present. |
39 | | end: Option<Pos>, |
40 | | }, |
41 | | /// The schema contained multiple query, mutation or subscription roots. |
42 | | MultipleRoots { |
43 | | /// The type of root that was duplicated. |
44 | | root: OperationType, |
45 | | /// The position of the schema. |
46 | | schema: Pos, |
47 | | /// The position of the second root. |
48 | | pos: Pos, |
49 | | }, |
50 | | /// The schema contained no query root. |
51 | | MissingQueryRoot { |
52 | | /// The position of the schema. |
53 | | pos: Pos, |
54 | | }, |
55 | | /// Multiple operations were found in a document with an anonymous one. |
56 | | MultipleOperations { |
57 | | /// The position of the anonymous operation. |
58 | | anonymous: Pos, |
59 | | /// The position of the other operation. |
60 | | operation: Pos, |
61 | | }, |
62 | | /// An operation is defined multiple times in a document. |
63 | | OperationDuplicated { |
64 | | /// The name of the operation. |
65 | | operation: Name, |
66 | | /// The position of the first definition. |
67 | | first: Pos, |
68 | | /// The position of the second definition. |
69 | | second: Pos, |
70 | | }, |
71 | | /// A fragment is defined multiple times in a document. |
72 | | FragmentDuplicated { |
73 | | /// The name of the fragment. |
74 | | fragment: Name, |
75 | | /// The position of the first definition. |
76 | | first: Pos, |
77 | | /// The position of the second definition. |
78 | | second: Pos, |
79 | | }, |
80 | | /// The document does not contain any operation. |
81 | | MissingOperation, |
82 | | /// Recursion limit exceeded. |
83 | | RecursionLimitExceeded, |
84 | | } |
85 | | |
86 | | impl Error { |
87 | | /// Get an iterator over the positions of the error. |
88 | | /// |
89 | | /// The iterator is ordered from most important to least important position. |
90 | | #[must_use] |
91 | 0 | pub fn positions(&self) -> ErrorPositions { |
92 | 0 | match self { |
93 | | Self::Syntax { |
94 | 0 | start, |
95 | 0 | end: Some(end), |
96 | | .. |
97 | 0 | } => ErrorPositions::new_2(*start, *end), |
98 | 0 | Self::Syntax { start, .. } => ErrorPositions::new_1(*start), |
99 | 0 | Self::MultipleRoots { schema, pos, .. } => ErrorPositions::new_2(*pos, *schema), |
100 | 0 | Self::MissingQueryRoot { pos } => ErrorPositions::new_1(*pos), |
101 | | Self::MultipleOperations { |
102 | 0 | anonymous, |
103 | 0 | operation, |
104 | 0 | } => ErrorPositions::new_2(*anonymous, *operation), |
105 | 0 | Self::OperationDuplicated { first, second, .. } => { |
106 | 0 | ErrorPositions::new_2(*second, *first) |
107 | | } |
108 | 0 | Self::FragmentDuplicated { first, second, .. } => { |
109 | 0 | ErrorPositions::new_2(*second, *first) |
110 | | } |
111 | 0 | Self::MissingOperation => ErrorPositions::new_0(), |
112 | 0 | Self::RecursionLimitExceeded => ErrorPositions::new_0(), |
113 | | } |
114 | 0 | } |
115 | | } |
116 | | |
117 | | impl Display for Error { |
118 | 0 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { |
119 | 0 | match self { |
120 | 0 | Self::Syntax { message, .. } => f.write_str(message), |
121 | 0 | Self::MissingQueryRoot { .. } => f.write_str("schema definition is missing query root"), |
122 | 0 | Self::MultipleRoots { root, .. } => { |
123 | 0 | write!(f, "multiple {} roots in schema definition", root) |
124 | | } |
125 | 0 | Self::MultipleOperations { .. } => f.write_str("document contains multiple operations"), |
126 | 0 | Self::OperationDuplicated { operation, .. } => { |
127 | 0 | write!(f, "operation {} is defined twice", operation) |
128 | | } |
129 | 0 | Self::FragmentDuplicated { fragment, .. } => { |
130 | 0 | write!(f, "fragment {} is defined twice", fragment) |
131 | | } |
132 | 0 | Self::MissingOperation => f.write_str("document does not contain an operation"), |
133 | 0 | Self::RecursionLimitExceeded => f.write_str("recursion limit exceeded."), |
134 | | } |
135 | 0 | } |
136 | | } |
137 | | |
138 | | impl std::error::Error for Error {} |
139 | | |
140 | | impl<R: RuleType> From<pest::error::Error<R>> for Error { |
141 | 0 | fn from(err: pest::error::Error<R>) -> Self { |
142 | 0 | let (start, end) = match err.line_col { |
143 | 0 | LineColLocation::Pos(at) => (at, None), |
144 | 0 | LineColLocation::Span(start, end) => (start, Some(end)), |
145 | | }; |
146 | | |
147 | 0 | Error::Syntax { |
148 | 0 | message: err.to_string(), |
149 | 0 | start: Pos::from(start), |
150 | 0 | end: end.map(Pos::from), |
151 | 0 | } |
152 | 0 | } Unexecuted instantiation: <async_graphql_parser::Error as core::convert::From<pest::error::Error<async_graphql_parser::parse::generated::Rule>>>::from Unexecuted instantiation: <async_graphql_parser::Error as core::convert::From<pest::error::Error<_>>>::from |
153 | | } |
154 | | |
155 | | /// An alias for `Result<T, Error>`. |
156 | | pub type Result<T> = std::result::Result<T, Error>; |
157 | | |
158 | | /// An iterator over the positions inside an error. |
159 | | /// |
160 | | /// Constructed from the `Error::positions` function. |
161 | | #[derive(Debug, Clone)] |
162 | | pub struct ErrorPositions(ErrorPositionsInner); |
163 | | |
164 | | impl ErrorPositions { |
165 | 0 | fn new_0() -> Self { |
166 | 0 | Self(ErrorPositionsInner::None) |
167 | 0 | } |
168 | 0 | fn new_1(a: Pos) -> Self { |
169 | 0 | Self(ErrorPositionsInner::One(a)) |
170 | 0 | } |
171 | 0 | fn new_2(a: Pos, b: Pos) -> Self { |
172 | 0 | Self(ErrorPositionsInner::Two(a, b)) |
173 | 0 | } |
174 | | } |
175 | | |
176 | | impl Iterator for ErrorPositions { |
177 | | type Item = Pos; |
178 | | |
179 | 0 | fn next(&mut self) -> Option<Self::Item> { |
180 | 0 | match self.0 { |
181 | 0 | ErrorPositionsInner::Two(a, b) => { |
182 | 0 | self.0 = ErrorPositionsInner::One(b); |
183 | 0 | Some(a) |
184 | | } |
185 | 0 | ErrorPositionsInner::One(a) => { |
186 | 0 | self.0 = ErrorPositionsInner::None; |
187 | 0 | Some(a) |
188 | | } |
189 | 0 | ErrorPositionsInner::None => None, |
190 | | } |
191 | 0 | } |
192 | | |
193 | 0 | fn size_hint(&self) -> (usize, Option<usize>) { |
194 | 0 | let len = self.len(); |
195 | 0 | (len, Some(len)) |
196 | 0 | } |
197 | | } |
198 | | |
199 | | impl DoubleEndedIterator for ErrorPositions { |
200 | 0 | fn next_back(&mut self) -> Option<Self::Item> { |
201 | 0 | match self.0 { |
202 | 0 | ErrorPositionsInner::Two(a, b) => { |
203 | 0 | self.0 = ErrorPositionsInner::One(a); |
204 | 0 | Some(b) |
205 | | } |
206 | 0 | ErrorPositionsInner::One(a) => { |
207 | 0 | self.0 = ErrorPositionsInner::None; |
208 | 0 | Some(a) |
209 | | } |
210 | 0 | ErrorPositionsInner::None => None, |
211 | | } |
212 | 0 | } |
213 | | } |
214 | | |
215 | | impl std::iter::FusedIterator for ErrorPositions {} |
216 | | |
217 | | impl ExactSizeIterator for ErrorPositions { |
218 | 0 | fn len(&self) -> usize { |
219 | 0 | match self.0 { |
220 | 0 | ErrorPositionsInner::Two(_, _) => 2, |
221 | 0 | ErrorPositionsInner::One(_) => 1, |
222 | 0 | ErrorPositionsInner::None => 0, |
223 | | } |
224 | 0 | } |
225 | | } |
226 | | |
227 | | impl Serialize for ErrorPositions { |
228 | 0 | fn serialize<S: Serializer>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> { |
229 | 0 | serializer.collect_seq(self.clone()) |
230 | 0 | } |
231 | | } |
232 | | |
233 | | #[derive(Debug, Clone, Copy)] |
234 | | enum ErrorPositionsInner { |
235 | | Two(Pos, Pos), |
236 | | One(Pos), |
237 | | None, |
238 | | } |