1mod parser;
2mod syntax_kind;
3mod syntax_node;
4
5use js_sys::{Array, Object, Reflect};
6use rowan::TextSize;
7use syntax_node::SyntaxNode;
8use wasm_bindgen::{prelude::wasm_bindgen, JsValue};
9
10use syntax_kind::SyntaxKind;
11
12#[wasm_bindgen]
13pub fn get_parse_tree(input: &str, offset: u32) -> JsValue {
14 let root = SyntaxNode::new_root(parser::parse_text(input));
15 build_js_tree(&root, TextSize::new(offset))
16}
17
18fn build_js_tree(node: &SyntaxNode, offset: TextSize) -> JsValue {
19 let obj = Object::new();
20 Reflect::set(
21 &obj,
22 &JsValue::from_str("kind"),
23 &JsValue::from_str(&format!("{:?}", node.kind())),
24 )
25 .unwrap();
26 Reflect::set(&obj, &JsValue::from_str("type"), &JsValue::from_str("node")).unwrap();
27 Reflect::set(
28 &obj,
29 &JsValue::from_str("active"),
30 &JsValue::from_bool(node.text_range().contains(offset)),
31 )
32 .unwrap();
33
34 let children = Array::from_iter(node.children_with_tokens().filter_map(|child| match child {
35 rowan::NodeOrToken::Node(node) => Some(build_js_tree(&node, offset)),
36 rowan::NodeOrToken::Token(token) if token.kind() != SyntaxKind::WHITESPACE => {
37 let token_obj = Object::new();
38 Reflect::set(
39 &token_obj,
40 &JsValue::from_str("kind"),
41 &JsValue::from_str(&format!("{:?}", token.kind())),
42 )
43 .unwrap();
44 Reflect::set(
45 &token_obj,
46 &JsValue::from_str("type"),
47 &JsValue::from_str("token"),
48 )
49 .unwrap();
50 Reflect::set(
51 &token_obj,
52 &JsValue::from_str("text"),
53 &JsValue::from_str(token.text()),
54 )
55 .unwrap();
56 Reflect::set(
57 &token_obj,
58 &JsValue::from_str("active"),
59 &JsValue::from_bool(token.text_range().contains(offset)),
60 )
61 .unwrap();
62 Some(token_obj.into())
63 }
64 _ => None,
65 }));
66 Reflect::set(&obj, &JsValue::from_str("children"), &children.into()).unwrap();
67 obj.into()
68}