Skip to main content

normalize_languages/
typst.rs

1//! Typst language support.
2
3use crate::{Import, Language, LanguageSymbols};
4use tree_sitter::Node;
5
6/// Typst language support.
7pub struct Typst;
8
9impl Language for Typst {
10    fn name(&self) -> &'static str {
11        "Typst"
12    }
13    fn extensions(&self) -> &'static [&'static str] {
14        &["typ"]
15    }
16    fn grammar_name(&self) -> &'static str {
17        "typst"
18    }
19
20    fn as_symbols(&self) -> Option<&dyn LanguageSymbols> {
21        Some(self)
22    }
23
24    fn extract_imports(&self, node: &Node, content: &str) -> Vec<Import> {
25        if node.kind() != "import" {
26            return Vec::new();
27        }
28
29        let text = &content[node.byte_range()];
30        vec![Import {
31            module: text.trim().to_string(),
32            names: Vec::new(),
33            alias: None,
34            is_wildcard: text.contains('*'),
35            is_relative: false,
36            line: node.start_position().row + 1,
37        }]
38    }
39
40    fn format_import(&self, import: &Import, names: Option<&[&str]>) -> String {
41        // Typst: #import "file.typ" or #import "file.typ": item1, item2
42        let names_to_use: Vec<&str> = names
43            .map(|n| n.to_vec())
44            .unwrap_or_else(|| import.names.iter().map(|s| s.as_str()).collect());
45        if names_to_use.is_empty() {
46            format!("#import \"{}\"", import.module)
47        } else if import.is_wildcard {
48            format!("#import \"{}\": *", import.module)
49        } else {
50            format!("#import \"{}\": {}", import.module, names_to_use.join(", "))
51        }
52    }
53}
54
55impl LanguageSymbols for Typst {}
56
57#[cfg(test)]
58mod tests {
59    use super::*;
60    use crate::validate_unused_kinds_audit;
61
62    #[test]
63    fn unused_node_kinds_audit() {
64        #[rustfmt::skip]
65        let documented_unused: &[&str] = &[
66            // Math mode
67            "formula",
68            // Control flow (not function definitions)
69            "return",
70            // Inline lambdas are not top-level definitions
71            "lambda",
72            // Loop constructs — not definition kinds
73            "for", "while",
74            // Module system — not a symbol definition
75            "import",
76            // Block expression — container body, not a top-level definition
77            "block",
78        ];
79        validate_unused_kinds_audit(&Typst, documented_unused)
80            .expect("Typst unused node kinds audit failed");
81    }
82}