swiftide_integrations/treesitter/
metadata_refs_defs_code.rs1use std::sync::Arc;
38
39use swiftide_core::{Transformer, indexing::TextNode};
40
41use crate::treesitter::{CodeParser, SupportedLanguages};
42use anyhow::{Context as _, Result};
43use async_trait::async_trait;
44
45pub const NAME_REFERENCES: &str = "References (code)";
46pub const NAME_DEFINITIONS: &str = "Definitions (code)";
47
48#[swiftide_macros::indexing_transformer(derive(skip_default))]
50pub struct MetadataRefsDefsCode {
51 code_parser: Arc<CodeParser>,
52}
53
54impl MetadataRefsDefsCode {
55 pub fn try_from_language(language: impl TryInto<SupportedLanguages>) -> Result<Self> {
61 let language: SupportedLanguages = language
62 .try_into()
63 .ok()
64 .context("Treesitter language not supported")?;
65
66 MetadataRefsDefsCode::builder()
67 .code_parser(CodeParser::from_language(language))
68 .build()
69 }
70}
71
72#[async_trait]
73impl Transformer for MetadataRefsDefsCode {
74 type Input = String;
75 type Output = String;
76 async fn transform_node(&self, mut node: TextNode) -> Result<TextNode> {
79 let refs_defs = self
80 .code_parser
81 .parse(&node.chunk)?
82 .references_and_definitions()?;
83
84 if !refs_defs.references.is_empty() {
85 node.metadata
86 .insert(NAME_REFERENCES.to_string(), refs_defs.references.join(","));
87 }
88
89 if !refs_defs.definitions.is_empty() {
90 node.metadata.insert(
91 NAME_DEFINITIONS.to_string(),
92 refs_defs.definitions.join(","),
93 );
94 }
95 Ok(node)
96 }
97}
98
99#[cfg(test)]
100mod test {
101
102 use super::*;
103 use test_case::test_case;
104
105 #[test_case("rust", "fn main() { println!(\"Hello, World!\"); }", "println", "main"; "rust")]
106 #[test_case("ruby", "def main; puts 'Hello, World!'; end", "puts", "main"; "ruby")]
107 #[test_case("python", "def main(): print('Hello, World!')", "print", "main"; "python")]
108 #[test_case("javascript", "function main() { console.log('Hello, World!'); }", "log", "main"; "javascript")]
109 #[test_case("typescript", "function main() { console.log('Hello, World!'); }", "log", "main"; "typescript")]
110 #[test_case("java", "public class Main { public static void main(String[] args) { System.out.println(\"Hello, World!\"); } }", "println", "Main,main"; "java")]
111 #[test_case("c-sharp", "public class Program { public static void Main(string[] args) { System.Console.WriteLine(\"Hello, World!\"); } }", "WriteLine", "Main,Program"; "c-sharp")]
112 #[tokio::test]
113 async fn assert_refs_defs_from_code(
114 lang: &str,
115 code: &str,
116 expected_references: &str,
117 expected_definitions: &str,
118 ) {
119 let transformer = MetadataRefsDefsCode::try_from_language(lang).unwrap();
120 let node = TextNode::new(code);
121
122 let node = transformer.transform_node(node).await.unwrap();
123
124 let references = node
125 .metadata
126 .get(NAME_REFERENCES)
127 .unwrap()
128 .as_str()
129 .unwrap()
130 .to_string();
131 let definitions = node
132 .metadata
133 .get(NAME_DEFINITIONS)
134 .unwrap()
135 .as_str()
136 .unwrap()
137 .to_string();
138
139 assert_eq!(references, expected_references);
140 assert_eq!(definitions, expected_definitions);
141 }
142}