Skip to main content

tree_sitter_harn/
lib.rs

1//! Harn language support for the tree-sitter parsing library.
2
3use tree_sitter_language::LanguageFn;
4
5extern "C" {
6    fn tree_sitter_harn() -> *const ();
7}
8
9/// The tree-sitter language function for Harn.
10pub const LANGUAGE: LanguageFn = unsafe { LanguageFn::from_raw(tree_sitter_harn) };
11
12/// The content of the generated `node-types.json` file.
13pub const NODE_TYPES: &str = include_str!("../../src/node-types.json");
14
15/// The syntax highlighting query for Harn.
16pub const HIGHLIGHTS_QUERY: &str = include_str!("../../queries/highlights.scm");
17
18/// The language injection query for Harn.
19pub const INJECTIONS_QUERY: &str = include_str!("../../queries/injections.scm");
20
21#[cfg(test)]
22mod tests {
23    use tree_sitter::{Query, QueryCursor, StreamingIterator};
24
25    #[test]
26    fn can_load_grammar() {
27        let mut parser = tree_sitter::Parser::new();
28        parser
29            .set_language(&super::LANGUAGE.into())
30            .expect("load Harn parser");
31    }
32
33    #[test]
34    fn bundled_queries_compile() {
35        let language = super::LANGUAGE.into();
36        tree_sitter::Query::new(&language, super::HIGHLIGHTS_QUERY)
37            .expect("highlight query should compile");
38        tree_sitter::Query::new(&language, super::INJECTIONS_QUERY)
39            .expect("injection query should compile");
40    }
41
42    #[test]
43    fn injection_query_captures_postgres_template_content() {
44        let source = r#"fn build_sql(user_id) {
45  let q = sql("""
46select *
47from users
48where id = {user_id}
49""", {user_id: user_id})
50  let named = named_sql("users_by_id", "one", "select * from users where id = {user_id}", {user_id: user_id})
51  let raw = query.sql(r"select * from users where name = {name}", {name: "Ada"})
52  let other = render("select * from ignored")
53}"#;
54
55        let language = super::LANGUAGE.into();
56        let mut parser = tree_sitter::Parser::new();
57        parser.set_language(&language).expect("load Harn parser");
58        let tree = parser.parse(source, None).expect("parse Harn source");
59        assert!(
60            !tree.root_node().has_error(),
61            "fixture should parse cleanly"
62        );
63
64        let query =
65            Query::new(&language, super::INJECTIONS_QUERY).expect("injection query should compile");
66        let capture_index = query
67            .capture_names()
68            .iter()
69            .position(|name| *name == "injection.content")
70            .expect("query should expose injection.content") as u32;
71
72        let mut cursor = QueryCursor::new();
73        let mut matches = cursor.matches(&query, tree.root_node(), source.as_bytes());
74        let mut captured = Vec::new();
75        while let Some(query_match) = matches.next() {
76            for capture in query_match.captures {
77                if capture.index == capture_index {
78                    captured.push(capture.node.utf8_text(source.as_bytes()).unwrap());
79                }
80            }
81        }
82
83        assert_eq!(
84            captured,
85            vec![
86                "\nselect *\nfrom users\nwhere id = {user_id}\n",
87                "select * from users where id = {user_id}",
88                "select * from users where name = {name}",
89            ]
90        );
91    }
92}