1use combine::easy::{Error, Errors};
2use combine::error::StreamError;
3use combine::sep_by1;
4use combine::{choice, eof, many, many1, optional, position};
5use combine::{parser, Parser, StdParseResult};
6
7use crate::common::{default_value, directives, parse_type, string, Text};
8use crate::helpers::{ident, kind, name, punct};
9use crate::schema::ast::*;
10use crate::schema::error::ParseError;
11use crate::tokenizer::{Kind as T, Token, TokenStream};
12
13pub fn schema<'a, S>(
14 input: &mut TokenStream<'a>,
15) -> StdParseResult<SchemaDefinition<'a, S>, TokenStream<'a>>
16where
17 S: Text<'a>,
18{
19 (
20 position().skip(ident("schema")),
21 parser(directives),
22 punct("{")
23 .with(many((kind(T::Name).skip(punct(":")), name::<'a, S>())))
24 .skip(punct("}")),
25 )
26 .flat_map(
27 |(position, directives, operations): (_, _, Vec<(Token, _)>)| {
28 let mut query = None;
29 let mut mutation = None;
30 let mut subscription = None;
31 let mut err = Errors::empty(position);
32 for (oper, type_name) in operations {
33 match oper.value {
34 "query" if query.is_some() => {
35 err.add_error(Error::unexpected_static_message(
36 "duplicate `query` operation",
37 ));
38 }
39 "query" => {
40 query = Some(type_name);
41 }
42 "mutation" if mutation.is_some() => {
43 err.add_error(Error::unexpected_static_message(
44 "duplicate `mutation` operation",
45 ));
46 }
47 "mutation" => {
48 mutation = Some(type_name);
49 }
50 "subscription" if subscription.is_some() => {
51 err.add_error(Error::unexpected_static_message(
52 "duplicate `subscription` operation",
53 ));
54 }
55 "subscription" => {
56 subscription = Some(type_name);
57 }
58 _ => {
59 err.add_error(Error::unexpected_token(oper));
60 err.add_error(Error::expected_static_message("query"));
61 err.add_error(Error::expected_static_message("mutation"));
62 err.add_error(Error::expected_static_message("subscription"));
63 }
64 }
65 }
66 if !err.errors.is_empty() {
67 return Err(err);
68 }
69 Ok(SchemaDefinition {
70 position,
71 directives,
72 query,
73 mutation,
74 subscription,
75 })
76 },
77 )
78 .parse_stream(input)
79 .into_result()
80}
81
82pub fn scalar_type<'a, T>(
83 input: &mut TokenStream<'a>,
84) -> StdParseResult<ScalarType<'a, T>, TokenStream<'a>>
85where
86 T: Text<'a>,
87{
88 (
89 position(),
90 ident("scalar").with(name::<'a, T>()),
91 parser(directives),
92 )
93 .map(|(position, name, directives)| ScalarType {
94 position,
95 description: None,
96 name,
97 directives,
98 })
99 .parse_stream(input)
100 .into_result()
101}
102
103pub fn scalar_type_extension<'a, T>(
104 input: &mut TokenStream<'a>,
105) -> StdParseResult<ScalarTypeExtension<'a, T>, TokenStream<'a>>
106where
107 T: Text<'a>,
108{
109 (
110 position(),
111 ident("scalar").with(name::<'a, T>()),
112 parser(directives),
113 )
114 .flat_map(|(position, name, directives)| {
115 if directives.is_empty() {
116 let mut e = Errors::empty(position);
117 e.add_error(Error::expected_static_message(
118 "Scalar type extension should contain at least \
119 one directive.",
120 ));
121 return Err(e);
122 }
123 Ok(ScalarTypeExtension {
124 position,
125 name,
126 directives,
127 })
128 })
129 .parse_stream(input)
130 .into_result()
131}
132
133pub fn implements_interfaces<'a, X>(
134 input: &mut TokenStream<'a>,
135) -> StdParseResult<Vec<X::Value>, TokenStream<'a>>
136where
137 X: Text<'a>,
138{
139 optional(
140 ident("implements")
141 .skip(optional(punct("&")))
142 .with(sep_by1(name::<'a, X>(), punct("&"))),
143 )
144 .map(|opt| opt.unwrap_or_default())
145 .parse_stream(input)
146 .into_result()
147}
148
149pub fn input_value<'a, X>(
150 input: &mut TokenStream<'a>,
151) -> StdParseResult<InputValue<'a, X>, TokenStream<'a>>
152where
153 X: Text<'a>,
154{
155 (
156 position(),
157 optional(parser(string)),
158 name::<'a, X>(),
159 punct(":").with(parser(parse_type)),
160 optional(punct("=").with(parser(default_value))),
161 parser(directives),
162 )
163 .map(
164 |(position, description, name, value_type, default_value, directives)| InputValue {
165 position,
166 description,
167 name,
168 value_type,
169 default_value,
170 directives,
171 },
172 )
173 .parse_stream(input)
174 .into_result()
175}
176
177pub fn arguments_definition<'a, T>(
178 input: &mut TokenStream<'a>,
179) -> StdParseResult<Vec<InputValue<'a, T>>, TokenStream<'a>>
180where
181 T: Text<'a>,
182{
183 optional(punct("(").with(many1(parser(input_value))).skip(punct(")")))
184 .map(|v| v.unwrap_or_default())
185 .parse_stream(input)
186 .into_result()
187}
188
189pub fn field<'a, S>(input: &mut TokenStream<'a>) -> StdParseResult<Field<'a, S>, TokenStream<'a>>
190where
191 S: Text<'a>,
192{
193 (
194 position(),
195 optional(parser(string)),
196 name::<'a, S>(),
197 parser(arguments_definition),
198 punct(":").with(parser(parse_type)),
199 parser(directives),
200 )
201 .map(
202 |(position, description, name, arguments, field_type, directives)| Field {
203 position,
204 description,
205 name,
206 arguments,
207 field_type,
208 directives,
209 },
210 )
211 .parse_stream(input)
212 .into_result()
213}
214
215pub fn fields<'a, S>(
216 input: &mut TokenStream<'a>,
217) -> StdParseResult<Vec<Field<'a, S>>, TokenStream<'a>>
218where
219 S: Text<'a>,
220{
221 optional(punct("{").with(many1(parser(field))).skip(punct("}")))
222 .map(|v| v.unwrap_or_default())
223 .parse_stream(input)
224 .into_result()
225}
226
227pub fn object_type<'a, S>(
228 input: &mut TokenStream<'a>,
229) -> StdParseResult<ObjectType<'a, S>, TokenStream<'a>>
230where
231 S: Text<'a>,
232{
233 (
234 position(),
235 ident("type").with(name::<'a, S>()),
236 parser(implements_interfaces::<S>),
237 parser(directives),
238 parser(fields),
239 )
240 .map(|(position, name, interfaces, directives, fields)| {
241 ObjectType {
242 position,
243 name,
244 directives,
245 fields,
246 implements_interfaces: interfaces,
247 description: None, }
249 })
250 .parse_stream(input)
251 .into_result()
252}
253
254pub fn object_type_extension<'a, S>(
255 input: &mut TokenStream<'a>,
256) -> StdParseResult<ObjectTypeExtension<'a, S>, TokenStream<'a>>
257where
258 S: Text<'a>,
259{
260 (
261 position(),
262 ident("type").with(name::<'a, S>()),
263 parser(implements_interfaces::<S>),
264 parser(directives),
265 parser(fields),
266 )
267 .flat_map(|(position, name, interfaces, directives, fields)| {
268 if interfaces.is_empty() && directives.is_empty() && fields.is_empty() {
269 let mut e = Errors::empty(position);
270 e.add_error(Error::expected_static_message(
271 "Object type extension should contain at least \
272 one interface, directive or field.",
273 ));
274 return Err(e);
275 }
276 Ok(ObjectTypeExtension {
277 position,
278 name,
279 directives,
280 fields,
281 implements_interfaces: interfaces,
282 })
283 })
284 .parse_stream(input)
285 .into_result()
286}
287
288pub fn interface_type<'a, T>(
289 input: &mut TokenStream<'a>,
290) -> StdParseResult<InterfaceType<'a, T>, TokenStream<'a>>
291where
292 T: Text<'a>,
293{
294 (
295 position(),
296 ident("interface").with(name::<'a, T>()),
297 parser(implements_interfaces::<T>),
298 parser(directives),
299 parser(fields),
300 )
301 .map(|(position, name, interfaces, directives, fields)| {
302 InterfaceType {
303 position,
304 name,
305 implements_interfaces: interfaces,
306 directives,
307 fields,
308 description: None, }
310 })
311 .parse_stream(input)
312 .into_result()
313}
314
315pub fn interface_type_extension<'a, T>(
316 input: &mut TokenStream<'a>,
317) -> StdParseResult<InterfaceTypeExtension<'a, T>, TokenStream<'a>>
318where
319 T: Text<'a>,
320{
321 (
322 position(),
323 ident("interface").with(name::<'a, T>()),
324 parser(implements_interfaces::<T>),
325 parser(directives),
326 parser(fields),
327 )
328 .flat_map(|(position, name, interfaces, directives, fields)| {
329 if directives.is_empty() && fields.is_empty() {
330 let mut e = Errors::empty(position);
331 e.add_error(Error::expected_static_message(
332 "Interface type extension should contain at least \
333 one directive or field.",
334 ));
335 return Err(e);
336 }
337 Ok(InterfaceTypeExtension {
338 position,
339 name,
340 implements_interfaces: interfaces,
341 directives,
342 fields,
343 })
344 })
345 .parse_stream(input)
346 .into_result()
347}
348
349pub fn union_members<'a, T>(
350 input: &mut TokenStream<'a>,
351) -> StdParseResult<Vec<T::Value>, TokenStream<'a>>
352where
353 T: Text<'a>,
354{
355 optional(punct("|"))
356 .with(sep_by1(name::<'a, T>(), punct("|")))
357 .parse_stream(input)
358 .into_result()
359}
360
361pub fn union_type<'a, T>(
362 input: &mut TokenStream<'a>,
363) -> StdParseResult<UnionType<'a, T>, TokenStream<'a>>
364where
365 T: Text<'a>,
366{
367 (
368 position(),
369 ident("union").with(name::<'a, T>()),
370 parser(directives),
371 optional(punct("=").with(parser(union_members::<T>))),
372 )
373 .map(|(position, name, directives, types)| {
374 UnionType {
375 position,
376 name,
377 directives,
378 types: types.unwrap_or_else(Vec::new),
379 description: None, }
381 })
382 .parse_stream(input)
383 .into_result()
384}
385
386pub fn union_type_extension<'a, T>(
387 input: &mut TokenStream<'a>,
388) -> StdParseResult<UnionTypeExtension<'a, T>, TokenStream<'a>>
389where
390 T: Text<'a>,
391{
392 (
393 position(),
394 ident("union").with(name::<'a, T>()),
395 parser(directives),
396 optional(punct("=").with(parser(union_members::<T>))),
397 )
398 .flat_map(|(position, name, directives, types)| {
399 if directives.is_empty() && types.is_none() {
400 let mut e = Errors::empty(position);
401 e.add_error(Error::expected_static_message(
402 "Union type extension should contain at least \
403 one directive or type.",
404 ));
405 return Err(e);
406 }
407 Ok(UnionTypeExtension {
408 position,
409 name,
410 directives,
411 types: types.unwrap_or_else(Vec::new),
412 })
413 })
414 .parse_stream(input)
415 .into_result()
416}
417
418pub fn enum_values<'a, T>(
419 input: &mut TokenStream<'a>,
420) -> StdParseResult<Vec<EnumValue<'a, T>>, TokenStream<'a>>
421where
422 T: Text<'a>,
423{
424 punct("{")
425 .with(many1(
426 (
427 position(),
428 optional(parser(string)),
429 name::<'a, T>(),
430 parser(directives),
431 )
432 .map(|(position, description, name, directives)| EnumValue {
433 position,
434 description,
435 name,
436 directives,
437 }),
438 ))
439 .skip(punct("}"))
440 .parse_stream(input)
441 .into_result()
442}
443
444pub fn enum_type<'a, T>(
445 input: &mut TokenStream<'a>,
446) -> StdParseResult<EnumType<'a, T>, TokenStream<'a>>
447where
448 T: Text<'a>,
449{
450 (
451 position(),
452 ident("enum").with(name::<'a, T>()),
453 parser(directives),
454 optional(parser(enum_values)),
455 )
456 .map(|(position, name, directives, values)| {
457 EnumType {
458 position,
459 name,
460 directives,
461 values: values.unwrap_or_else(Vec::new),
462 description: None, }
464 })
465 .parse_stream(input)
466 .into_result()
467}
468
469pub fn enum_type_extension<'a, T>(
470 input: &mut TokenStream<'a>,
471) -> StdParseResult<EnumTypeExtension<'a, T>, TokenStream<'a>>
472where
473 T: Text<'a>,
474{
475 (
476 position(),
477 ident("enum").with(name::<'a, T>()),
478 parser(directives),
479 optional(parser(enum_values)),
480 )
481 .flat_map(|(position, name, directives, values)| {
482 if directives.is_empty() && values.is_none() {
483 let mut e = Errors::empty(position);
484 e.add_error(Error::expected_static_message(
485 "Enum type extension should contain at least \
486 one directive or value.",
487 ));
488 return Err(e);
489 }
490 Ok(EnumTypeExtension {
491 position,
492 name,
493 directives,
494 values: values.unwrap_or_else(Vec::new),
495 })
496 })
497 .parse_stream(input)
498 .into_result()
499}
500
501pub fn input_fields<'a, T>(
502 input: &mut TokenStream<'a>,
503) -> StdParseResult<Vec<InputValue<'a, T>>, TokenStream<'a>>
504where
505 T: Text<'a>,
506{
507 optional(punct("{").with(many1(parser(input_value))).skip(punct("}")))
508 .map(|v| v.unwrap_or_default())
509 .parse_stream(input)
510 .into_result()
511}
512
513pub fn input_object_type<'a, T>(
514 input: &mut TokenStream<'a>,
515) -> StdParseResult<InputObjectType<'a, T>, TokenStream<'a>>
516where
517 T: Text<'a>,
518{
519 (
520 position(),
521 ident("input").with(name::<'a, T>()),
522 parser(directives),
523 parser(input_fields),
524 )
525 .map(|(position, name, directives, fields)| {
526 InputObjectType {
527 position,
528 name,
529 directives,
530 fields,
531 description: None, }
533 })
534 .parse_stream(input)
535 .into_result()
536}
537
538pub fn input_object_type_extension<'a, T>(
539 input: &mut TokenStream<'a>,
540) -> StdParseResult<InputObjectTypeExtension<'a, T>, TokenStream<'a>>
541where
542 T: Text<'a>,
543{
544 (
545 position(),
546 ident("input").with(name::<'a, T>()),
547 parser(directives),
548 parser(input_fields),
549 )
550 .flat_map(|(position, name, directives, fields)| {
551 if directives.is_empty() && fields.is_empty() {
552 let mut e = Errors::empty(position);
553 e.add_error(Error::expected_static_message(
554 "Input object type extension should contain at least \
555 one directive or field.",
556 ));
557 return Err(e);
558 }
559 Ok(InputObjectTypeExtension {
560 position,
561 name,
562 directives,
563 fields,
564 })
565 })
566 .parse_stream(input)
567 .into_result()
568}
569
570pub fn directive_locations<'a>(
571 input: &mut TokenStream<'a>,
572) -> StdParseResult<Vec<DirectiveLocation>, TokenStream<'a>> {
573 optional(optional(punct("|")).with(sep_by1(
574 kind(T::Name).and_then(|tok| tok.value.parse::<DirectiveLocation>()),
575 punct("|"),
576 )))
577 .map(|opt| opt.unwrap_or_default())
578 .parse_stream(input)
579 .into_result()
580}
581
582pub fn directive_definition<'a, T>(
583 input: &mut TokenStream<'a>,
584) -> StdParseResult<DirectiveDefinition<'a, T>, TokenStream<'a>>
585where
586 T: Text<'a>,
587{
588 (
589 position(),
590 ident("directive").and(punct("@")).with(name::<'a, T>()),
591 parser(arguments_definition),
592 optional(ident("repeatable")),
593 ident("on").with(parser(directive_locations)),
594 )
595 .map(|(position, name, arguments, repeatable, locations)| {
596 DirectiveDefinition {
597 position,
598 name,
599 arguments,
600 locations,
601 repeatable: repeatable.is_some(),
602 description: None, }
604 })
605 .parse_stream(input)
606 .into_result()
607}
608
609pub fn described_definition<'a, T>(
610 input: &mut TokenStream<'a>,
611) -> StdParseResult<Definition<'a, T>, TokenStream<'a>>
612where
613 T: Text<'a>,
614{
615 use self::TypeDefinition::*;
616 (
617 optional(parser(string)),
618 choice((
619 choice((
620 parser(scalar_type).map(Scalar),
621 parser(object_type).map(Object),
622 parser(interface_type).map(Interface),
623 parser(union_type).map(Union),
624 parser(enum_type).map(Enum),
625 parser(input_object_type).map(InputObject),
626 ))
627 .map(Definition::TypeDefinition),
628 parser(directive_definition).map(Definition::DirectiveDefinition),
629 )),
630 )
631 .map(|(descr, mut def)| {
635 use crate::schema::ast::Definition::TypeDefinition as T;
636 use crate::schema::ast::Definition::*;
637 use crate::schema::ast::TypeDefinition::*;
638 match def {
639 T(Scalar(ref mut s)) => s.description = descr,
640 T(Object(ref mut o)) => o.description = descr,
641 T(Interface(ref mut i)) => i.description = descr,
642 T(Union(ref mut u)) => u.description = descr,
643 T(Enum(ref mut e)) => e.description = descr,
644 T(InputObject(ref mut o)) => o.description = descr,
645 DirectiveDefinition(ref mut d) => d.description = descr,
646 SchemaDefinition(_) => unreachable!(),
647 TypeExtension(_) => unreachable!(),
648 }
649 def
650 })
651 .parse_stream(input)
652 .into_result()
653}
654
655pub fn type_extension<'a, T>(
656 input: &mut TokenStream<'a>,
657) -> StdParseResult<TypeExtension<'a, T>, TokenStream<'a>>
658where
659 T: Text<'a>,
660{
661 ident("extend")
662 .with(choice((
663 parser(scalar_type_extension).map(TypeExtension::Scalar),
664 parser(object_type_extension).map(TypeExtension::Object),
665 parser(interface_type_extension).map(TypeExtension::Interface),
666 parser(union_type_extension).map(TypeExtension::Union),
667 parser(enum_type_extension).map(TypeExtension::Enum),
668 parser(input_object_type_extension).map(TypeExtension::InputObject),
669 )))
670 .parse_stream(input)
671 .into_result()
672}
673
674pub fn definition<'a, T>(
675 input: &mut TokenStream<'a>,
676) -> StdParseResult<Definition<'a, T>, TokenStream<'a>>
677where
678 T: Text<'a>,
679{
680 choice((
681 parser(schema).map(Definition::SchemaDefinition),
682 parser(type_extension).map(Definition::TypeExtension),
683 parser(described_definition),
684 ))
685 .parse_stream(input)
686 .into_result()
687}
688
689pub fn parse_schema<'a, T>(s: &'a str) -> Result<Document<'a, T>, ParseError>
691where
692 T: Text<'a>,
693{
694 let mut tokens = TokenStream::new(s);
695 let (doc, _) = many1(parser(definition))
696 .map(|d| Document { definitions: d })
697 .skip(eof())
698 .parse_stream(&mut tokens)
699 .into_result()
700 .map_err(|e| e.into_inner().error)?;
701
702 Ok(doc)
703}
704
705#[cfg(test)]
706mod test {
707 use super::parse_schema;
708 use crate::position::Pos;
709 use crate::schema::grammar::*;
710
711 fn ast(s: &str) -> Document<String> {
712 parse_schema::<String>(s).unwrap().to_owned()
713 }
714
715 #[test]
716 fn one_field() {
717 assert_eq!(
718 ast("schema { query: Query }"),
719 Document {
720 definitions: vec![Definition::SchemaDefinition(SchemaDefinition {
721 position: Pos { line: 1, column: 1 },
722 directives: vec![],
723 query: Some("Query".into()),
724 mutation: None,
725 subscription: None
726 })],
727 }
728 );
729 }
730}