oak_graphql/builder/
mod.rs1use crate::{
2 ast,
3 ast::*,
4 language::GraphQLLanguage,
5 lexer::token_type::GraphQLTokenType,
6 parser::{GraphQLParser, element_type::GraphQLElementType},
7};
8use oak_core::{Builder, BuilderCache, GreenNode, OakDiagnostics, OakError, Parser, Range, RedNode, RedTree, SourceText, TextEdit, TokenType, builder::BuildOutput, source::Source};
9
10#[derive(Clone)]
12pub struct GraphQLBuilder<'config> {
13 config: &'config GraphQLLanguage,
14}
15
16impl<'config> GraphQLBuilder<'config> {
17 pub fn new(config: &'config GraphQLLanguage) -> Self {
19 Self { config }
20 }
21
22 fn get_text(&self, span: Range<usize>, source: &SourceText) -> String {
23 source.text()[span].to_string()
24 }
25}
26
27impl<'config> Builder<GraphQLLanguage> for GraphQLBuilder<'config> {
28 fn build<'a, S: Source + ?Sized>(&self, source: &S, edits: &[TextEdit], _cache: &'a mut impl BuilderCache<GraphQLLanguage>) -> BuildOutput<GraphQLLanguage> {
29 let parser = GraphQLParser::new(self.config);
30 let mut parse_cache = oak_core::parser::session::ParseSession::<GraphQLLanguage>::default();
31 let parse_result = parser.parse(source, edits, &mut parse_cache);
32
33 match parse_result.result {
34 Ok(green_tree) => {
35 let source_text = SourceText::new(source.get_text_in((0..source.length()).into()).into_owned());
36 match self.build_root(green_tree, &source_text) {
37 Ok(ast_root) => OakDiagnostics { result: Ok(ast_root), diagnostics: parse_result.diagnostics },
38 Err(build_error) => {
39 let mut diagnostics = parse_result.diagnostics;
40 diagnostics.push(build_error.clone());
41 OakDiagnostics { result: Err(build_error), diagnostics }
42 }
43 }
44 }
45 Err(parse_error) => OakDiagnostics { result: Err(parse_error), diagnostics: parse_result.diagnostics },
46 }
47 }
48}
49
50impl<'config> GraphQLBuilder<'config> {
51 pub(crate) fn build_root<'a>(&self, green_tree: &'a GreenNode<'a, GraphQLLanguage>, source: &SourceText) -> Result<GraphQLRoot, OakError> {
52 let root_node = RedNode::new(green_tree, 0);
53 let mut definitions = Vec::new();
54
55 for child in root_node.children() {
56 if let RedTree::Node(n) = child {
57 match n.green.kind {
58 GraphQLElementType::QueryKeyword | GraphQLElementType::MutationKeyword | GraphQLElementType::SubscriptionKeyword => {
59 definitions.push(Definition::Operation(self.build_operation_definition(n, source)?));
60 }
61 GraphQLElementType::FragmentKeyword => {
62 definitions.push(Definition::Fragment(self.build_fragment_definition(n, source)?));
63 }
64 GraphQLElementType::SchemaKeyword => {
65 definitions.push(Definition::Schema(self.build_schema_definition(n, source)?));
66 }
67 GraphQLElementType::TypeKeyword => {
68 definitions.push(Definition::Type(self.build_type_definition(n, source)?));
69 }
70 _ => {
71 }
73 }
74 }
75 }
76
77 Ok(GraphQLRoot { document: Document { definitions, span: root_node.span() } })
78 }
79
80 fn build_operation_definition<'a>(&self, node: RedNode<'a, GraphQLLanguage>, source: &SourceText) -> Result<OperationDefinition, OakError> {
81 let mut operation_type = OperationType::Query;
82 let mut name = None;
83
84 for child in node.children() {
85 match child {
86 RedTree::Leaf(t) => match t.kind {
87 GraphQLTokenType::QueryKeyword => operation_type = OperationType::Query,
88 GraphQLTokenType::MutationKeyword => operation_type = OperationType::Mutation,
89 GraphQLTokenType::SubscriptionKeyword => operation_type = OperationType::Subscription,
90 GraphQLTokenType::Name => name = Some(self.get_text(t.span.clone(), source)),
91 _ => {}
92 },
93 _ => {}
94 }
95 }
96
97 Ok(OperationDefinition { operation_type, name, span: node.span() })
98 }
99
100 fn build_fragment_definition<'a>(&self, node: RedNode<'a, GraphQLLanguage>, source: &SourceText) -> Result<FragmentDefinition, OakError> {
101 let mut name = String::new();
102
103 for child in node.children() {
104 if let RedTree::Leaf(t) = child {
105 if t.kind == GraphQLTokenType::Name {
106 name = self.get_text(t.span.clone(), source);
107 }
108 }
109 }
110
111 Ok(FragmentDefinition { name, span: node.span() })
112 }
113
114 fn build_schema_definition<'a>(&self, node: RedNode<'a, GraphQLLanguage>, _source: &SourceText) -> Result<SchemaDefinition, OakError> {
115 Ok(SchemaDefinition { span: node.span() })
116 }
117
118 fn build_type_definition<'a>(&self, node: RedNode<'a, GraphQLLanguage>, source: &SourceText) -> Result<TypeDefinition, OakError> {
119 let mut name = String::new();
120
121 for child in node.children() {
122 if let RedTree::Leaf(t) = child {
123 if t.kind == GraphQLTokenType::Name {
124 name = self.get_text(t.span.clone(), source);
125 }
126 }
127 }
128
129 Ok(TypeDefinition { name, span: node.span() })
130 }
131}