1pub mod ast;
2mod parser;
3mod rules;
4pub mod syntax_kind;
5mod syntax_node;
6mod utils;
7
8#[cfg(target_arch = "wasm32")]
9use js_sys::{Array, Object, Reflect};
10pub use parser::{guess_operation_type, ParseError, TopEntryPoint};
11#[cfg(target_arch = "wasm32")]
12use rowan::TextSize;
13use syntax_kind::SyntaxKind;
14pub use syntax_node::*;
15pub use utils::*;
16#[cfg(target_arch = "wasm32")]
17use wasm_bindgen::{prelude::wasm_bindgen, JsValue};
18
19use crate::parser::lex;
20
21pub fn parse_query(input: &str) -> (SyntaxNode, Vec<ParseError>) {
22 let (root, errors) = parser::parse_text(input, parser::TopEntryPoint::QueryUnit);
23 (SyntaxNode::new_root(root), errors)
24}
25
26pub fn parse_update(input: &str) -> (SyntaxNode, Vec<ParseError>) {
27 let (root, errors) = parser::parse_text(input, parser::TopEntryPoint::UpdateUnit);
28 (SyntaxNode::new_root(root), errors)
29}
30
31pub fn parse(input: &str) -> (SyntaxNode, Vec<ParseError>) {
32 match guess_operation_type(input) {
33 Some(TopEntryPoint::QueryUnit) | None => parse_query(input),
34 Some(TopEntryPoint::UpdateUnit) => parse_update(input),
35 }
36}
37
38pub enum QueryType {
39 SelectQuery,
40 ConstructQuery,
41 DescribeQuery,
42 AskQuery,
43}
44
45pub fn guess_query_type(input: &str) -> Option<QueryType> {
46 let tokens = lex(input);
47 tokens.iter().find_map(|(token, _)| match token.kind() {
48 SyntaxKind::SELECT => Some(QueryType::SelectQuery),
49 SyntaxKind::CONSTRUCT => Some(QueryType::ConstructQuery),
50 SyntaxKind::ASK => Some(QueryType::AskQuery),
51 SyntaxKind::DESCRIBE => Some(QueryType::DescribeQuery),
52 _ => None,
53 })
54}
55
56#[cfg(test)]
57mod tests;
58
59#[cfg(target_arch = "wasm32")]
60#[wasm_bindgen]
61pub fn get_parse_tree(input: &str, offset: u32) -> JsValue {
62 let root = parse(input).0;
63 build_js_tree(&root, TextSize::new(offset))
64}
65
66#[cfg(target_arch = "wasm32")]
67fn build_js_tree(node: &SyntaxNode, offset: TextSize) -> JsValue {
68 let obj = Object::new();
69 Reflect::set(
70 &obj,
71 &JsValue::from_str("kind"),
72 &JsValue::from_str(&format!("{:?}", node.kind())),
73 )
74 .unwrap();
75 Reflect::set(&obj, &JsValue::from_str("type"), &JsValue::from_str("node")).unwrap();
76 Reflect::set(
77 &obj,
78 &JsValue::from_str("active"),
79 &JsValue::from_bool(node.text_range().contains(offset)),
80 )
81 .unwrap();
82
83 let children = Array::from_iter(node.children_with_tokens().filter_map(|child| match child {
84 rowan::NodeOrToken::Node(node) => Some(build_js_tree(&node, offset)),
85 rowan::NodeOrToken::Token(token) => {
86 let token_obj = Object::new();
87 Reflect::set(
88 &token_obj,
89 &JsValue::from_str("kind"),
90 &JsValue::from_str(&format!("{:?}", token.kind())),
91 )
92 .unwrap();
93 Reflect::set(
94 &token_obj,
95 &JsValue::from_str("type"),
96 &JsValue::from_str("token"),
97 )
98 .unwrap();
99 Reflect::set(
100 &token_obj,
101 &JsValue::from_str("text"),
102 &JsValue::from_str(token.text()),
103 )
104 .unwrap();
105 Reflect::set(
106 &token_obj,
107 &JsValue::from_str("active"),
108 &JsValue::from_bool(token.text_range().contains(offset)),
109 )
110 .unwrap();
111 Some(token_obj.into())
112 }
113 }));
114 Reflect::set(&obj, &JsValue::from_str("children"), &children.into()).unwrap();
115 obj.into()
116}