use tree_sitter_language::LanguageFn;
extern "C" {
fn tree_sitter_htmlx() -> *const ();
}
pub const LANGUAGE: LanguageFn = unsafe { LanguageFn::from_raw(tree_sitter_htmlx) };
pub fn language() -> tree_sitter::Language {
LANGUAGE.into()
}
pub const HIGHLIGHTS_QUERY: &str = include_str!("../queries/highlights.scm");
pub const INJECTIONS_QUERY: &str = include_str!("../queries/injections.scm");
pub const NODE_TYPES: &str = include_str!("../src/node-types.json");
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_can_load_grammar() {
let mut parser = tree_sitter::Parser::new();
parser
.set_language(&LANGUAGE.into())
.expect("Failed to load HTMLX grammar");
}
#[test]
fn test_parse_simple_html() {
let mut parser = tree_sitter::Parser::new();
parser.set_language(&LANGUAGE.into()).unwrap();
let source = "<div>Hello</div>";
let tree = parser.parse(source, None).unwrap();
assert!(!tree.root_node().has_error());
assert_eq!(tree.root_node().kind(), "document");
}
#[test]
fn test_parse_expression() {
let mut parser = tree_sitter::Parser::new();
parser.set_language(&LANGUAGE.into()).unwrap();
let source = "<div>{name}</div>";
let tree = parser.parse(source, None).unwrap();
assert!(!tree.root_node().has_error());
}
#[test]
fn test_parse_expression_attribute() {
let mut parser = tree_sitter::Parser::new();
parser.set_language(&LANGUAGE.into()).unwrap();
let source = r#"<input value={text} />"#;
let tree = parser.parse(source, None).unwrap();
assert!(!tree.root_node().has_error());
}
#[test]
fn test_parse_shorthand_attribute() {
let mut parser = tree_sitter::Parser::new();
parser.set_language(&LANGUAGE.into()).unwrap();
let source = r#"<div {hidden} {id}></div>"#;
let tree = parser.parse(source, None).unwrap();
assert!(!tree.root_node().has_error());
}
#[test]
fn test_parse_spread_attribute() {
let mut parser = tree_sitter::Parser::new();
parser.set_language(&LANGUAGE.into()).unwrap();
let source = r#"<Component {...props} />"#;
let tree = parser.parse(source, None).unwrap();
assert!(!tree.root_node().has_error());
}
#[test]
fn test_parse_directive_attribute() {
let mut parser = tree_sitter::Parser::new();
parser.set_language(&LANGUAGE.into()).unwrap();
let source = r#"<input bind:value={name} on:input={handleInput} />"#;
let tree = parser.parse(source, None).unwrap();
assert!(!tree.root_node().has_error());
}
#[test]
fn test_parse_nested_expressions() {
let mut parser = tree_sitter::Parser::new();
parser.set_language(&LANGUAGE.into()).unwrap();
let source = r#"<div>{items.map(item => item.name)}</div>"#;
let tree = parser.parse(source, None).unwrap();
assert!(!tree.root_node().has_error());
}
#[test]
fn test_highlights_query_includes_html_captures() {
let language = language();
let query = tree_sitter::Query::new(&language, HIGHLIGHTS_QUERY)
.expect("HTMLX highlights query should compile");
let captures = query.capture_names();
for capture in ["tag", "attribute", "string", "punctuation.bracket"] {
assert!(
captures.iter().any(|name| *name == capture),
"missing @{capture} from HTMLX highlights query"
);
}
}
}