1use std::{
2 collections::HashMap,
3 fmt::{self, Display, Formatter},
4};
5
6use async_graphql_value::Value;
7
8use crate::{
9 InputType, Name, Pos, Positioned, ServerError, ServerResult, Variables,
10 parser::types::{
11 Directive, ExecutableDocument, Field, FragmentDefinition, FragmentSpread, InlineFragment,
12 OperationDefinition, OperationType, Selection, SelectionSet, TypeCondition,
13 VariableDefinition,
14 },
15 registry::{self, MetaType, MetaTypeName},
16};
17
18#[doc(hidden)]
19pub struct VisitorContext<'a> {
20 pub(crate) registry: &'a registry::Registry,
21 pub(crate) variables: Option<&'a Variables>,
22 pub(crate) errors: Vec<RuleError>,
23 type_stack: Vec<Option<&'a registry::MetaType>>,
24 input_type: Vec<Option<MetaTypeName<'a>>>,
25 fragments: &'a HashMap<Name, Positioned<FragmentDefinition>>,
26}
27
28impl<'a> VisitorContext<'a> {
29 pub(crate) fn new(
30 registry: &'a registry::Registry,
31 doc: &'a ExecutableDocument,
32 variables: Option<&'a Variables>,
33 ) -> Self {
34 Self {
35 registry,
36 variables,
37 errors: Default::default(),
38 type_stack: Default::default(),
39 input_type: Default::default(),
40 fragments: &doc.fragments,
41 }
42 }
43
44 pub(crate) fn report_error<T: Into<String>>(&mut self, locations: Vec<Pos>, msg: T) {
45 self.errors.push(RuleError::new(locations, msg));
46 }
47
48 pub(crate) fn append_errors(&mut self, errors: Vec<RuleError>) {
49 self.errors.extend(errors);
50 }
51
52 pub(crate) fn with_type<F: FnMut(&mut VisitorContext<'a>)>(
53 &mut self,
54 ty: Option<&'a registry::MetaType>,
55 mut f: F,
56 ) {
57 self.type_stack.push(ty);
58 f(self);
59 self.type_stack.pop();
60 }
61
62 pub(crate) fn with_input_type<F: FnMut(&mut VisitorContext<'a>)>(
63 &mut self,
64 ty: Option<MetaTypeName<'a>>,
65 mut f: F,
66 ) {
67 self.input_type.push(ty);
68 f(self);
69 self.input_type.pop();
70 }
71
72 pub(crate) fn parent_type(&self) -> Option<&'a registry::MetaType> {
73 if self.type_stack.len() >= 2 {
74 self.type_stack
75 .get(self.type_stack.len() - 2)
76 .copied()
77 .flatten()
78 } else {
79 None
80 }
81 }
82
83 pub(crate) fn current_type(&self) -> Option<&'a registry::MetaType> {
84 self.type_stack.last().copied().flatten()
85 }
86
87 pub(crate) fn is_known_fragment(&self, name: &str) -> bool {
88 self.fragments.contains_key(name)
89 }
90
91 pub(crate) fn fragment(&self, name: &str) -> Option<&'a Positioned<FragmentDefinition>> {
92 self.fragments.get(name)
93 }
94
95 #[doc(hidden)]
96 pub fn param_value<T: InputType>(
97 &self,
98 variable_definitions: &[Positioned<VariableDefinition>],
99 field: &Field,
100 name: &str,
101 default: Option<fn() -> T>,
102 ) -> ServerResult<T> {
103 let value = field.get_argument(name).cloned();
104
105 if value.is_none() {
106 if let Some(default) = default {
107 return Ok(default());
108 }
109 }
110
111 let (pos, value) = match value {
112 Some(value) => {
113 let pos = value.pos;
114 (
115 pos,
116 Some(value.node.into_const_with(|name| {
117 variable_definitions
118 .iter()
119 .find(|def| def.node.name.node == name)
120 .and_then(|def| {
121 if let Some(variables) = self.variables {
122 variables
123 .get(&def.node.name.node)
124 .or_else(|| def.node.default_value())
125 } else {
126 None
127 }
128 })
129 .cloned()
130 .ok_or_else(|| {
131 ServerError::new(
132 format!("Variable {} is not defined.", name),
133 Some(pos),
134 )
135 })
136 })?),
137 )
138 }
139 None => (Pos::default(), None),
140 };
141
142 T::parse(value).map_err(|e| e.into_server_error(pos))
143 }
144}
145
146#[derive(Copy, Clone, Eq, PartialEq)]
147pub(crate) enum VisitMode {
148 Normal,
149 Inline,
150}
151
152pub(crate) trait Visitor<'a> {
153 fn mode(&self) -> VisitMode {
154 VisitMode::Normal
155 }
156
157 fn enter_document(&mut self, _ctx: &mut VisitorContext<'a>, _doc: &'a ExecutableDocument) {}
158 fn exit_document(&mut self, _ctx: &mut VisitorContext<'a>, _doc: &'a ExecutableDocument) {}
159
160 fn enter_operation_definition(
161 &mut self,
162 _ctx: &mut VisitorContext<'a>,
163 _name: Option<&'a Name>,
164 _operation_definition: &'a Positioned<OperationDefinition>,
165 ) {
166 }
167 fn exit_operation_definition(
168 &mut self,
169 _ctx: &mut VisitorContext<'a>,
170 _name: Option<&'a Name>,
171 _operation_definition: &'a Positioned<OperationDefinition>,
172 ) {
173 }
174
175 fn enter_fragment_definition(
176 &mut self,
177 _ctx: &mut VisitorContext<'a>,
178 _name: &'a Name,
179 _fragment_definition: &'a Positioned<FragmentDefinition>,
180 ) {
181 }
182 fn exit_fragment_definition(
183 &mut self,
184 _ctx: &mut VisitorContext<'a>,
185 _name: &'a Name,
186 _fragment_definition: &'a Positioned<FragmentDefinition>,
187 ) {
188 }
189
190 fn enter_variable_definition(
191 &mut self,
192 _ctx: &mut VisitorContext<'a>,
193 _variable_definition: &'a Positioned<VariableDefinition>,
194 ) {
195 }
196 fn exit_variable_definition(
197 &mut self,
198 _ctx: &mut VisitorContext<'a>,
199 _variable_definition: &'a Positioned<VariableDefinition>,
200 ) {
201 }
202
203 fn enter_directive(
204 &mut self,
205 _ctx: &mut VisitorContext<'a>,
206 _directive: &'a Positioned<Directive>,
207 ) {
208 }
209 fn exit_directive(
210 &mut self,
211 _ctx: &mut VisitorContext<'a>,
212 _directive: &'a Positioned<Directive>,
213 ) {
214 }
215
216 fn enter_argument(
217 &mut self,
218 _ctx: &mut VisitorContext<'a>,
219 _name: &'a Positioned<Name>,
220 _value: &'a Positioned<Value>,
221 ) {
222 }
223 fn exit_argument(
224 &mut self,
225 _ctx: &mut VisitorContext<'a>,
226 _name: &'a Positioned<Name>,
227 _value: &'a Positioned<Value>,
228 ) {
229 }
230
231 fn enter_selection_set(
232 &mut self,
233 _ctx: &mut VisitorContext<'a>,
234 _selection_set: &'a Positioned<SelectionSet>,
235 ) {
236 }
237 fn exit_selection_set(
238 &mut self,
239 _ctx: &mut VisitorContext<'a>,
240 _selection_set: &'a Positioned<SelectionSet>,
241 ) {
242 }
243
244 fn enter_selection(
245 &mut self,
246 _ctx: &mut VisitorContext<'a>,
247 _selection: &'a Positioned<Selection>,
248 ) {
249 }
250 fn exit_selection(
251 &mut self,
252 _ctx: &mut VisitorContext<'a>,
253 _selection: &'a Positioned<Selection>,
254 ) {
255 }
256
257 fn enter_field(&mut self, _ctx: &mut VisitorContext<'a>, _field: &'a Positioned<Field>) {}
258 fn exit_field(&mut self, _ctx: &mut VisitorContext<'a>, _field: &'a Positioned<Field>) {}
259
260 fn enter_fragment_spread(
261 &mut self,
262 _ctx: &mut VisitorContext<'a>,
263 _fragment_spread: &'a Positioned<FragmentSpread>,
264 ) {
265 }
266 fn exit_fragment_spread(
267 &mut self,
268 _ctx: &mut VisitorContext<'a>,
269 _fragment_spread: &'a Positioned<FragmentSpread>,
270 ) {
271 }
272
273 fn enter_inline_fragment(
274 &mut self,
275 _ctx: &mut VisitorContext<'a>,
276 _inline_fragment: &'a Positioned<InlineFragment>,
277 ) {
278 }
279 fn exit_inline_fragment(
280 &mut self,
281 _ctx: &mut VisitorContext<'a>,
282 _inline_fragment: &'a Positioned<InlineFragment>,
283 ) {
284 }
285
286 fn enter_input_value(
287 &mut self,
288 _ctx: &mut VisitorContext<'a>,
289 _pos: Pos,
290 _expected_type: &Option<MetaTypeName<'a>>,
291 _value: &'a Value,
292 ) {
293 }
294 fn exit_input_value(
295 &mut self,
296 _ctx: &mut VisitorContext<'a>,
297 _pos: Pos,
298 _expected_type: &Option<MetaTypeName<'a>>,
299 _value: &Value,
300 ) {
301 }
302}
303
304pub(crate) struct VisitorNil;
305
306impl VisitorNil {
307 pub(crate) fn with<V>(self, visitor: V) -> VisitorCons<V, Self> {
308 VisitorCons(visitor, self)
309 }
310}
311
312pub(crate) struct VisitorCons<A, B>(A, B);
313
314impl<A, B> VisitorCons<A, B> {
315 pub(crate) const fn with<V>(self, visitor: V) -> VisitorCons<V, Self> {
316 VisitorCons(visitor, self)
317 }
318}
319
320impl Visitor<'_> for VisitorNil {}
321
322impl<'a, A, B> Visitor<'a> for VisitorCons<A, B>
323where
324 A: Visitor<'a> + 'a,
325 B: Visitor<'a> + 'a,
326{
327 fn mode(&self) -> VisitMode {
328 self.0.mode()
329 }
330
331 fn enter_document(&mut self, ctx: &mut VisitorContext<'a>, doc: &'a ExecutableDocument) {
332 self.0.enter_document(ctx, doc);
333 self.1.enter_document(ctx, doc);
334 }
335
336 fn exit_document(&mut self, ctx: &mut VisitorContext<'a>, doc: &'a ExecutableDocument) {
337 self.0.exit_document(ctx, doc);
338 self.1.exit_document(ctx, doc);
339 }
340
341 fn enter_operation_definition(
342 &mut self,
343 ctx: &mut VisitorContext<'a>,
344 name: Option<&'a Name>,
345 operation_definition: &'a Positioned<OperationDefinition>,
346 ) {
347 self.0
348 .enter_operation_definition(ctx, name, operation_definition);
349 self.1
350 .enter_operation_definition(ctx, name, operation_definition);
351 }
352
353 fn exit_operation_definition(
354 &mut self,
355 ctx: &mut VisitorContext<'a>,
356 name: Option<&'a Name>,
357 operation_definition: &'a Positioned<OperationDefinition>,
358 ) {
359 self.0
360 .exit_operation_definition(ctx, name, operation_definition);
361 self.1
362 .exit_operation_definition(ctx, name, operation_definition);
363 }
364
365 fn enter_fragment_definition(
366 &mut self,
367 ctx: &mut VisitorContext<'a>,
368 name: &'a Name,
369 fragment_definition: &'a Positioned<FragmentDefinition>,
370 ) {
371 self.0
372 .enter_fragment_definition(ctx, name, fragment_definition);
373 self.1
374 .enter_fragment_definition(ctx, name, fragment_definition);
375 }
376
377 fn exit_fragment_definition(
378 &mut self,
379 ctx: &mut VisitorContext<'a>,
380 name: &'a Name,
381 fragment_definition: &'a Positioned<FragmentDefinition>,
382 ) {
383 self.0
384 .exit_fragment_definition(ctx, name, fragment_definition);
385 self.1
386 .exit_fragment_definition(ctx, name, fragment_definition);
387 }
388
389 fn enter_variable_definition(
390 &mut self,
391 ctx: &mut VisitorContext<'a>,
392 variable_definition: &'a Positioned<VariableDefinition>,
393 ) {
394 self.0.enter_variable_definition(ctx, variable_definition);
395 self.1.enter_variable_definition(ctx, variable_definition);
396 }
397
398 fn exit_variable_definition(
399 &mut self,
400 ctx: &mut VisitorContext<'a>,
401 variable_definition: &'a Positioned<VariableDefinition>,
402 ) {
403 self.0.exit_variable_definition(ctx, variable_definition);
404 self.1.exit_variable_definition(ctx, variable_definition);
405 }
406
407 fn enter_directive(
408 &mut self,
409 ctx: &mut VisitorContext<'a>,
410 directive: &'a Positioned<Directive>,
411 ) {
412 self.0.enter_directive(ctx, directive);
413 self.1.enter_directive(ctx, directive);
414 }
415
416 fn exit_directive(
417 &mut self,
418 ctx: &mut VisitorContext<'a>,
419 directive: &'a Positioned<Directive>,
420 ) {
421 self.0.exit_directive(ctx, directive);
422 self.1.exit_directive(ctx, directive);
423 }
424
425 fn enter_argument(
426 &mut self,
427 ctx: &mut VisitorContext<'a>,
428 name: &'a Positioned<Name>,
429 value: &'a Positioned<Value>,
430 ) {
431 self.0.enter_argument(ctx, name, value);
432 self.1.enter_argument(ctx, name, value);
433 }
434
435 fn exit_argument(
436 &mut self,
437 ctx: &mut VisitorContext<'a>,
438 name: &'a Positioned<Name>,
439 value: &'a Positioned<Value>,
440 ) {
441 self.0.exit_argument(ctx, name, value);
442 self.1.exit_argument(ctx, name, value);
443 }
444
445 fn enter_selection_set(
446 &mut self,
447 ctx: &mut VisitorContext<'a>,
448 selection_set: &'a Positioned<SelectionSet>,
449 ) {
450 self.0.enter_selection_set(ctx, selection_set);
451 self.1.enter_selection_set(ctx, selection_set);
452 }
453
454 fn exit_selection_set(
455 &mut self,
456 ctx: &mut VisitorContext<'a>,
457 selection_set: &'a Positioned<SelectionSet>,
458 ) {
459 self.0.exit_selection_set(ctx, selection_set);
460 self.1.exit_selection_set(ctx, selection_set);
461 }
462
463 fn enter_selection(
464 &mut self,
465 ctx: &mut VisitorContext<'a>,
466 selection: &'a Positioned<Selection>,
467 ) {
468 self.0.enter_selection(ctx, selection);
469 self.1.enter_selection(ctx, selection);
470 }
471
472 fn exit_selection(
473 &mut self,
474 ctx: &mut VisitorContext<'a>,
475 selection: &'a Positioned<Selection>,
476 ) {
477 self.0.exit_selection(ctx, selection);
478 self.1.exit_selection(ctx, selection);
479 }
480
481 fn enter_field(&mut self, ctx: &mut VisitorContext<'a>, field: &'a Positioned<Field>) {
482 self.0.enter_field(ctx, field);
483 self.1.enter_field(ctx, field);
484 }
485
486 fn exit_field(&mut self, ctx: &mut VisitorContext<'a>, field: &'a Positioned<Field>) {
487 self.0.exit_field(ctx, field);
488 self.1.exit_field(ctx, field);
489 }
490
491 fn enter_fragment_spread(
492 &mut self,
493 ctx: &mut VisitorContext<'a>,
494 fragment_spread: &'a Positioned<FragmentSpread>,
495 ) {
496 self.0.enter_fragment_spread(ctx, fragment_spread);
497 self.1.enter_fragment_spread(ctx, fragment_spread);
498 }
499
500 fn exit_fragment_spread(
501 &mut self,
502 ctx: &mut VisitorContext<'a>,
503 fragment_spread: &'a Positioned<FragmentSpread>,
504 ) {
505 self.0.exit_fragment_spread(ctx, fragment_spread);
506 self.1.exit_fragment_spread(ctx, fragment_spread);
507 }
508
509 fn enter_inline_fragment(
510 &mut self,
511 ctx: &mut VisitorContext<'a>,
512 inline_fragment: &'a Positioned<InlineFragment>,
513 ) {
514 self.0.enter_inline_fragment(ctx, inline_fragment);
515 self.1.enter_inline_fragment(ctx, inline_fragment);
516 }
517
518 fn exit_inline_fragment(
519 &mut self,
520 ctx: &mut VisitorContext<'a>,
521 inline_fragment: &'a Positioned<InlineFragment>,
522 ) {
523 self.0.exit_inline_fragment(ctx, inline_fragment);
524 self.1.exit_inline_fragment(ctx, inline_fragment);
525 }
526}
527
528pub(crate) fn visit<'a, V: Visitor<'a>>(
529 v: &mut V,
530 ctx: &mut VisitorContext<'a>,
531 doc: &'a ExecutableDocument,
532) {
533 v.enter_document(ctx, doc);
534
535 for (name, fragment) in &doc.fragments {
536 ctx.with_type(
537 ctx.registry
538 .types
539 .get(fragment.node.type_condition.node.on.node.as_str()),
540 |ctx| visit_fragment_definition(v, ctx, name, fragment),
541 )
542 }
543
544 for (name, operation) in doc.operations.iter() {
545 visit_operation_definition(v, ctx, name, operation);
546 }
547
548 v.exit_document(ctx, doc);
549}
550
551fn visit_operation_definition<'a, V: Visitor<'a>>(
552 v: &mut V,
553 ctx: &mut VisitorContext<'a>,
554 name: Option<&'a Name>,
555 operation: &'a Positioned<OperationDefinition>,
556) {
557 v.enter_operation_definition(ctx, name, operation);
558 let root_name = match &operation.node.ty {
559 OperationType::Query => Some(&*ctx.registry.query_type),
560 OperationType::Mutation => ctx.registry.mutation_type.as_deref(),
561 OperationType::Subscription => ctx.registry.subscription_type.as_deref(),
562 };
563 if let Some(root_name) = root_name {
564 ctx.with_type(Some(&ctx.registry.types[root_name]), |ctx| {
565 visit_variable_definitions(v, ctx, &operation.node.variable_definitions);
566 visit_directives(v, ctx, &operation.node.directives);
567 visit_selection_set(v, ctx, &operation.node.selection_set);
568 });
569 } else {
570 ctx.report_error(
571 vec![operation.pos],
572 format!("Schema is not configured for {}s.", operation.node.ty),
574 );
575 }
576 v.exit_operation_definition(ctx, name, operation);
577}
578
579fn visit_selection_set<'a, V: Visitor<'a>>(
580 v: &mut V,
581 ctx: &mut VisitorContext<'a>,
582 selection_set: &'a Positioned<SelectionSet>,
583) {
584 if !selection_set.node.items.is_empty() {
585 v.enter_selection_set(ctx, selection_set);
586 for selection in &selection_set.node.items {
587 visit_selection(v, ctx, selection);
588 }
589 v.exit_selection_set(ctx, selection_set);
590 }
591}
592
593fn visit_selection<'a, V: Visitor<'a>>(
594 v: &mut V,
595 ctx: &mut VisitorContext<'a>,
596 selection: &'a Positioned<Selection>,
597) {
598 v.enter_selection(ctx, selection);
599 match &selection.node {
600 Selection::Field(field) => {
601 if field.node.name.node != "__typename" {
602 ctx.with_type(
603 ctx.current_type()
604 .and_then(|ty| ty.field_by_name(&field.node.name.node))
605 .and_then(|schema_field| {
606 ctx.registry.concrete_type_by_name(&schema_field.ty)
607 }),
608 |ctx| {
609 visit_field(v, ctx, field);
610 },
611 );
612 } else if ctx.current_type().map(|ty| match ty {
613 MetaType::Object {
614 is_subscription, ..
615 } => *is_subscription,
616 _ => false,
617 }) == Some(true)
618 {
619 ctx.report_error(
620 vec![field.pos],
621 "Unknown field \"__typename\" on type \"Subscription\".",
622 );
623 }
624 }
625 Selection::FragmentSpread(fragment_spread) => {
626 visit_fragment_spread(v, ctx, fragment_spread)
627 }
628 Selection::InlineFragment(inline_fragment) => {
629 if let Some(TypeCondition { on: name }) = &inline_fragment
630 .node
631 .type_condition
632 .as_ref()
633 .map(|c| &c.node)
634 {
635 ctx.with_type(ctx.registry.types.get(name.node.as_str()), |ctx| {
636 visit_inline_fragment(v, ctx, inline_fragment)
637 });
638 } else {
639 visit_inline_fragment(v, ctx, inline_fragment)
640 }
641 }
642 }
643 v.exit_selection(ctx, selection);
644}
645
646fn visit_field<'a, V: Visitor<'a>>(
647 v: &mut V,
648 ctx: &mut VisitorContext<'a>,
649 field: &'a Positioned<Field>,
650) {
651 v.enter_field(ctx, field);
652
653 for (name, value) in &field.node.arguments {
654 v.enter_argument(ctx, name, value);
655 let expected_ty = ctx
656 .parent_type()
657 .and_then(|ty| ty.field_by_name(&field.node.name.node))
658 .and_then(|schema_field| schema_field.args.get(&*name.node))
659 .map(|input_ty| MetaTypeName::create(&input_ty.ty));
660 ctx.with_input_type(expected_ty, |ctx| {
661 visit_input_value(v, ctx, field.pos, expected_ty, &value.node)
662 });
663 v.exit_argument(ctx, name, value);
664 }
665
666 visit_directives(v, ctx, &field.node.directives);
667 visit_selection_set(v, ctx, &field.node.selection_set);
668 v.exit_field(ctx, field);
669}
670
671fn visit_input_value<'a, V: Visitor<'a>>(
672 v: &mut V,
673 ctx: &mut VisitorContext<'a>,
674 pos: Pos,
675 expected_ty: Option<MetaTypeName<'a>>,
676 value: &'a Value,
677) {
678 v.enter_input_value(ctx, pos, &expected_ty, value);
679
680 match value {
681 Value::List(values) => {
682 if let Some(expected_ty) = expected_ty {
683 let elem_ty = expected_ty.unwrap_non_null();
684 if let MetaTypeName::List(expected_ty) = elem_ty {
685 values.iter().for_each(|value| {
686 visit_input_value(
687 v,
688 ctx,
689 pos,
690 Some(MetaTypeName::create(expected_ty)),
691 value,
692 )
693 });
694 }
695 }
696 }
697 Value::Object(values) => {
698 if let Some(expected_ty) = expected_ty {
699 let expected_ty = expected_ty.unwrap_non_null();
700 if let MetaTypeName::Named(expected_ty) = expected_ty {
701 if let Some(MetaType::InputObject { input_fields, .. }) = ctx
702 .registry
703 .types
704 .get(MetaTypeName::concrete_typename(expected_ty))
705 {
706 for (item_key, item_value) in values {
707 if let Some(input_value) = input_fields.get(item_key.as_str()) {
708 visit_input_value(
709 v,
710 ctx,
711 pos,
712 Some(MetaTypeName::create(&input_value.ty)),
713 item_value,
714 );
715 }
716 }
717 }
718 }
719 }
720 }
721 _ => {}
722 }
723
724 v.exit_input_value(ctx, pos, &expected_ty, value);
725}
726
727fn visit_variable_definitions<'a, V: Visitor<'a>>(
728 v: &mut V,
729 ctx: &mut VisitorContext<'a>,
730 variable_definitions: &'a [Positioned<VariableDefinition>],
731) {
732 for d in variable_definitions {
733 v.enter_variable_definition(ctx, d);
734 v.exit_variable_definition(ctx, d);
735 }
736}
737
738fn visit_directives<'a, V: Visitor<'a>>(
739 v: &mut V,
740 ctx: &mut VisitorContext<'a>,
741 directives: &'a [Positioned<Directive>],
742) {
743 for d in directives {
744 v.enter_directive(ctx, d);
745
746 let schema_directive = ctx.registry.directives.get(d.node.name.node.as_str());
747
748 for (name, value) in &d.node.arguments {
749 v.enter_argument(ctx, name, value);
750 let expected_ty = schema_directive
751 .and_then(|schema_directive| schema_directive.args.get(&*name.node))
752 .map(|input_ty| MetaTypeName::create(&input_ty.ty));
753 ctx.with_input_type(expected_ty, |ctx| {
754 visit_input_value(v, ctx, d.pos, expected_ty, &value.node)
755 });
756 v.exit_argument(ctx, name, value);
757 }
758
759 v.exit_directive(ctx, d);
760 }
761}
762
763fn visit_fragment_definition<'a, V: Visitor<'a>>(
764 v: &mut V,
765 ctx: &mut VisitorContext<'a>,
766 name: &'a Name,
767 fragment: &'a Positioned<FragmentDefinition>,
768) {
769 if v.mode() == VisitMode::Normal {
770 v.enter_fragment_definition(ctx, name, fragment);
771 visit_directives(v, ctx, &fragment.node.directives);
772 visit_selection_set(v, ctx, &fragment.node.selection_set);
773 v.exit_fragment_definition(ctx, name, fragment);
774 }
775}
776
777fn visit_fragment_spread<'a, V: Visitor<'a>>(
778 v: &mut V,
779 ctx: &mut VisitorContext<'a>,
780 fragment_spread: &'a Positioned<FragmentSpread>,
781) {
782 v.enter_fragment_spread(ctx, fragment_spread);
783 visit_directives(v, ctx, &fragment_spread.node.directives);
784 if v.mode() == VisitMode::Inline {
785 if let Some(fragment) = ctx
786 .fragments
787 .get(fragment_spread.node.fragment_name.node.as_str())
788 {
789 visit_selection_set(v, ctx, &fragment.node.selection_set);
790 }
791 }
792 v.exit_fragment_spread(ctx, fragment_spread);
793}
794
795fn visit_inline_fragment<'a, V: Visitor<'a>>(
796 v: &mut V,
797 ctx: &mut VisitorContext<'a>,
798 inline_fragment: &'a Positioned<InlineFragment>,
799) {
800 v.enter_inline_fragment(ctx, inline_fragment);
801 visit_directives(v, ctx, &inline_fragment.node.directives);
802 visit_selection_set(v, ctx, &inline_fragment.node.selection_set);
803 v.exit_inline_fragment(ctx, inline_fragment);
804}
805
806#[derive(Debug, PartialEq)]
807pub(crate) struct RuleError {
808 pub(crate) locations: Vec<Pos>,
809 pub(crate) message: String,
810}
811
812impl RuleError {
813 pub(crate) fn new(locations: Vec<Pos>, msg: impl Into<String>) -> Self {
814 Self {
815 locations,
816 message: msg.into(),
817 }
818 }
819}
820
821impl Display for RuleError {
822 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
823 for (idx, loc) in self.locations.iter().enumerate() {
824 if idx == 0 {
825 write!(f, "[")?;
826 } else {
827 write!(f, ", ")?;
828 }
829
830 write!(f, "{}:{}", loc.line, loc.column)?;
831
832 if idx == self.locations.len() - 1 {
833 write!(f, "] ")?;
834 }
835 }
836
837 write!(f, "{}", self.message)?;
838 Ok(())
839 }
840}
841
842impl From<RuleError> for ServerError {
843 fn from(e: RuleError) -> Self {
844 Self {
845 message: e.message,
846 source: None,
847 locations: e.locations,
848 path: Vec::new(),
849 extensions: None,
850 }
851 }
852}