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