Skip to main content

sdivi_patterns/queries/
mod.rs

1//! Per-category node-kind classification rules.
2//!
3//! Each sub-module declares the tree-sitter node kinds that map to a built-in
4//! pattern category. Classification is performed by [`category_for_node_kind`],
5//! which returns the category name or `None` if the node kind is unrecognised.
6//!
7//! Category names are stable from Milestone 6 forward. Renaming any name is a
8//! breaking change requiring a `MIGRATION_NOTES.md` entry.
9
10pub mod async_patterns;
11pub mod error_handling;
12pub mod resource_management;
13pub mod state_management;
14pub mod type_assertions;
15
16/// All built-in category names in stable alphabetical order.
17///
18/// # Examples
19///
20/// ```rust
21/// use sdivi_patterns::queries::ALL_CATEGORIES;
22///
23/// assert!(ALL_CATEGORIES.contains(&"error_handling"));
24/// assert!(ALL_CATEGORIES.contains(&"async_patterns"));
25/// assert_eq!(ALL_CATEGORIES.len(), 5);
26/// ```
27pub const ALL_CATEGORIES: &[&str] = &[
28    "async_patterns",
29    "error_handling",
30    "resource_management",
31    "state_management",
32    "type_assertions",
33];
34
35/// Maps a tree-sitter `node_kind` to the built-in category it belongs to.
36///
37/// Returns `None` if the node kind does not belong to any category.
38/// The `_language` parameter is reserved for future per-language overrides.
39///
40/// # Examples
41///
42/// ```rust
43/// use sdivi_patterns::queries::category_for_node_kind;
44///
45/// assert_eq!(category_for_node_kind("try_expression", "rust"), Some("error_handling"));
46/// assert_eq!(category_for_node_kind("await_expression", "rust"), Some("async_patterns"));
47/// assert_eq!(category_for_node_kind("unknown_node", "rust"), None);
48/// ```
49pub fn category_for_node_kind(node_kind: &str, _language: &str) -> Option<&'static str> {
50    if error_handling::NODE_KINDS.contains(&node_kind) {
51        Some("error_handling")
52    } else if async_patterns::NODE_KINDS.contains(&node_kind) {
53        Some("async_patterns")
54    } else if state_management::NODE_KINDS.contains(&node_kind) {
55        Some("state_management")
56    } else if type_assertions::NODE_KINDS.contains(&node_kind) {
57        Some("type_assertions")
58    } else if resource_management::NODE_KINDS.contains(&node_kind) {
59        Some("resource_management")
60    } else {
61        None
62    }
63}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68
69    #[test]
70    fn try_expression_is_error_handling() {
71        assert_eq!(
72            category_for_node_kind("try_expression", "rust"),
73            Some("error_handling")
74        );
75    }
76
77    #[test]
78    fn await_expression_is_async_patterns() {
79        assert_eq!(
80            category_for_node_kind("await_expression", "rust"),
81            Some("async_patterns")
82        );
83    }
84
85    #[test]
86    fn closure_expression_is_state_management() {
87        assert_eq!(
88            category_for_node_kind("closure_expression", "rust"),
89            Some("state_management")
90        );
91    }
92
93    #[test]
94    fn macro_invocation_is_resource_management() {
95        assert_eq!(
96            category_for_node_kind("macro_invocation", "rust"),
97            Some("resource_management")
98        );
99    }
100
101    #[test]
102    fn unknown_node_kind_returns_none() {
103        assert_eq!(category_for_node_kind("unknown_xyz", "rust"), None);
104    }
105
106    #[test]
107    fn all_categories_has_five_entries() {
108        assert_eq!(ALL_CATEGORIES.len(), 5);
109    }
110}