Skip to content

Commit eca72ce

Browse files
committed
Add SchemaVisitor trait and functions for walking a schema ast
1 parent 88ecf9a commit eca72ce

File tree

2 files changed

+219
-0
lines changed

2 files changed

+219
-0
lines changed

src/schema/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ mod ast;
44
mod grammar;
55
mod error;
66
mod format;
7+
pub mod schema_visitor;
78

89
pub use self::ast::*;
910
pub use self::error::ParseError;

src/schema/schema_visitor.rs

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
//! Schema syntax tree traversal.
2+
//!
3+
//! Each method of [`SchemaVisitor`] is a hook that can be overridden to customize the behavior when
4+
//! visiting the corresponding type of node. By default, the methods don't do anything. The actual
5+
//! walking of the ast is done by the `walk_*` functions. So to run a visitor over the whole
6+
//! document you should use [`walk_document`].
7+
//!
8+
//! Example:
9+
//!
10+
//! ```
11+
//! use graphql_parser::schema::{
12+
//! ObjectType,
13+
//! parse_schema,
14+
//! schema_visitor::{SchemaVisitor, walk_document},
15+
//! };
16+
//!
17+
//! struct ObjectTypesCounter {
18+
//! count: usize,
19+
//! }
20+
//!
21+
//! impl ObjectTypesCounter {
22+
//! fn new() -> Self {
23+
//! Self { count: 0 }
24+
//! }
25+
//! }
26+
//!
27+
//! impl<'ast> SchemaVisitor<'ast> for ObjectTypesCounter {
28+
//! fn visit_object_type(&mut self, node: &'ast ObjectType) {
29+
//! self.count += 1;
30+
//! }
31+
//! }
32+
//!
33+
//! fn main() {
34+
//! let mut number_of_type = ObjectTypesCounter::new();
35+
//!
36+
//! let doc = parse_schema(r#"
37+
//! schema {
38+
//! query: Query
39+
//! }
40+
//!
41+
//! type Query {
42+
//! users: [User!]!
43+
//! }
44+
//!
45+
//! type User {
46+
//! id: ID!
47+
//! }
48+
//! "#).expect("Failed to parse schema");
49+
//!
50+
//! walk_document(&mut number_of_type, &doc);
51+
//!
52+
//! assert_eq!(number_of_type.count, 2);
53+
//! }
54+
//! ```
55+
//!
56+
//! [`SchemaVisitor`]: /graphql_parser/schema/schema_visitor/trait.SchemaVisitor.html
57+
//! [`walk_document`]: /graphql_parser/schema/schema_visitor/fn.walk_document.html
58+
59+
#![allow(unused_variables)]
60+
61+
use super::ast::*;
62+
63+
/// Trait for easy schema syntax tree traversal.
64+
///
65+
/// See [module docs](/graphql_parser/schema/schema_visitor/index.html) for more info.
66+
pub trait SchemaVisitor<'ast> {
67+
fn visit_document(&mut self, doc: &'ast Document) {}
68+
69+
fn visit_schema_definition(&mut self, node: &'ast SchemaDefinition) {}
70+
71+
fn visit_directive_definition(&mut self, node: &'ast DirectiveDefinition) {}
72+
73+
fn visit_type_definition(&mut self, node: &'ast TypeDefinition) {}
74+
75+
fn visit_scalar_type(&mut self, node: &'ast ScalarType) {}
76+
77+
fn visit_object_type(&mut self, node: &'ast ObjectType) {}
78+
79+
fn visit_interface_type(&mut self, node: &'ast InterfaceType) {}
80+
81+
fn visit_union_type(&mut self, node: &'ast UnionType) {}
82+
83+
fn visit_enum_type(&mut self, node: &'ast EnumType) {}
84+
85+
fn visit_input_object_type(&mut self, node: &'ast InputObjectType) {}
86+
87+
fn visit_type_extension(&mut self, node: &'ast TypeExtension) {}
88+
89+
fn visit_scalar_type_extension(&mut self, node: &'ast ScalarTypeExtension) {}
90+
91+
fn visit_object_type_extension(&mut self, node: &'ast ObjectTypeExtension) {}
92+
93+
fn visit_interface_type_extension(&mut self, node: &'ast InterfaceTypeExtension) {}
94+
95+
fn visit_union_type_extension(&mut self, node: &'ast UnionTypeExtension) {}
96+
97+
fn visit_enum_type_extension(&mut self, node: &'ast EnumTypeExtension) {}
98+
99+
fn visit_input_object_type_extension(&mut self, node: &'ast InputObjectTypeExtension) {}
100+
}
101+
102+
/// Walk a schema syntax tree and call the visitor methods for each type of node.
103+
///
104+
/// This function is how you should initiate a visitor.
105+
pub fn walk_document<'ast, V: SchemaVisitor<'ast>>(visitor: &mut V, doc: &'ast Document) {
106+
use super::ast::Definition::*;
107+
108+
for def in &doc.definitions {
109+
match def {
110+
SchemaDefinition(inner) => {
111+
visitor.visit_schema_definition(inner);
112+
walk_schema_definition(visitor, inner);
113+
}
114+
TypeDefinition(inner) => {
115+
visitor.visit_type_definition(inner);
116+
walk_type_definition(visitor, inner);
117+
}
118+
TypeExtension(inner) => {
119+
visitor.visit_type_extension(inner);
120+
walk_type_extension(visitor, inner);
121+
}
122+
DirectiveDefinition(inner) => {
123+
visitor.visit_directive_definition(inner);
124+
walk_directive_definition(visitor, inner);
125+
}
126+
}
127+
}
128+
}
129+
130+
fn walk_schema_definition<'ast, V: SchemaVisitor<'ast>>(visitor: &mut V, node: &'ast SchemaDefinition) {}
131+
132+
fn walk_directive_definition<'ast, V: SchemaVisitor<'ast>>(visitor: &mut V, node: &'ast DirectiveDefinition) {}
133+
134+
fn walk_type_definition<'ast, V: SchemaVisitor<'ast>>(visitor: &mut V, node: &'ast TypeDefinition) {
135+
use super::ast::TypeDefinition::*;
136+
137+
match node {
138+
Scalar(inner) => {
139+
visitor.visit_scalar_type(inner);
140+
walk_scalar_type(visitor, inner);
141+
}
142+
Object(inner) => {
143+
visitor.visit_object_type(inner);
144+
walk_object_type(visitor, inner);
145+
}
146+
Interface(inner) => {
147+
visitor.visit_interface_type(inner);
148+
walk_interface_type(visitor, inner);
149+
}
150+
Union(inner) => {
151+
visitor.visit_union_type(inner);
152+
walk_union_type(visitor, inner);
153+
}
154+
Enum(inner) => {
155+
visitor.visit_enum_type(inner);
156+
walk_enum_type(visitor, inner);
157+
}
158+
InputObject(inner) => {
159+
visitor.visit_input_object_type(inner);
160+
walk_input_object_type(visitor, inner);
161+
}
162+
}
163+
}
164+
165+
fn walk_scalar_type<'ast, V: SchemaVisitor<'ast>>(visitor: &mut V, node: &'ast ScalarType) {}
166+
167+
fn walk_object_type<'ast, V: SchemaVisitor<'ast>>(visitor: &mut V, node: &'ast ObjectType) {}
168+
169+
fn walk_interface_type<'ast, V: SchemaVisitor<'ast>>(visitor: &mut V, node: &'ast InterfaceType) {}
170+
171+
fn walk_union_type<'ast, V: SchemaVisitor<'ast>>(visitor: &mut V, node: &'ast UnionType) {}
172+
173+
fn walk_enum_type<'ast, V: SchemaVisitor<'ast>>(visitor: &mut V, node: &'ast EnumType) {}
174+
175+
fn walk_input_object_type<'ast, V: SchemaVisitor<'ast>>(visitor: &mut V, node: &'ast InputObjectType) {}
176+
177+
fn walk_type_extension<'ast, V: SchemaVisitor<'ast>>(visitor: &mut V, node: &'ast TypeExtension) {
178+
use super::ast::TypeExtension::*;
179+
180+
match node {
181+
Scalar(inner) => {
182+
visitor.visit_scalar_type_extension(inner);
183+
walk_scalar_type_extension(visitor, inner);
184+
}
185+
Object(inner) => {
186+
visitor.visit_object_type_extension(inner);
187+
walk_object_type_extension(visitor, inner);
188+
}
189+
Interface(inner) => {
190+
visitor.visit_interface_type_extension(inner);
191+
walk_interface_type_extension(visitor, inner);
192+
}
193+
Union(inner) => {
194+
visitor.visit_union_type_extension(inner);
195+
walk_union_type_extension(visitor, inner);
196+
}
197+
Enum(inner) => {
198+
visitor.visit_enum_type_extension(inner);
199+
walk_enum_type_extension(visitor, inner);
200+
}
201+
InputObject(inner) => {
202+
visitor.visit_input_object_type_extension(inner);
203+
walk_input_object_type_extension(visitor, inner);
204+
}
205+
}
206+
}
207+
208+
fn walk_scalar_type_extension<'ast, V: SchemaVisitor<'ast>>(visitor: &mut V, node: &'ast ScalarTypeExtension) {}
209+
210+
fn walk_object_type_extension<'ast, V: SchemaVisitor<'ast>>(visitor: &mut V, node: &'ast ObjectTypeExtension) {}
211+
212+
fn walk_interface_type_extension<'ast, V: SchemaVisitor<'ast>>(visitor: &mut V, node: &'ast InterfaceTypeExtension) {}
213+
214+
fn walk_union_type_extension<'ast, V: SchemaVisitor<'ast>>(visitor: &mut V, node: &'ast UnionTypeExtension) {}
215+
216+
fn walk_enum_type_extension<'ast, V: SchemaVisitor<'ast>>(visitor: &mut V, node: &'ast EnumTypeExtension) {}
217+
218+
fn walk_input_object_type_extension<'ast, V: SchemaVisitor<'ast>>(visitor: &mut V, node: &'ast InputObjectTypeExtension) {}

0 commit comments

Comments
 (0)