ricecoder_external_lsp/mapping/
completion.rs1use crate::error::Result;
7use crate::types::CompletionMappingRules;
8use serde_json::Value;
9
10use super::transformer::OutputTransformer;
11
12#[derive(Debug, Clone)]
14pub struct CompletionMapper {
15 transformer: OutputTransformer,
16}
17
18impl CompletionMapper {
19 pub fn new() -> Self {
21 Self {
22 transformer: OutputTransformer::new(),
23 }
24 }
25
26 pub fn with_transformer(transformer: OutputTransformer) -> Self {
28 Self { transformer }
29 }
30
31 pub fn map(&self, response: &Value, rules: &CompletionMappingRules) -> Result<Vec<Value>> {
42 self.transformer.transform_completion(response, rules)
43 }
44
45 pub fn map_item(&self, item: &Value, rules: &CompletionMappingRules) -> Result<Value> {
50 let wrapped = serde_json::json!({
52 "result": {
53 "items": [item]
54 }
55 });
56
57 let default_rules = CompletionMappingRules {
59 items_path: "$.result.items".to_string(),
60 field_mappings: rules.field_mappings.clone(),
61 transform: rules.transform.clone(),
62 };
63
64 let results = self.transformer.transform_completion(&wrapped, &default_rules)?;
65
66 if results.is_empty() {
67 return Err(crate::error::ExternalLspError::TransformationError(
68 "Failed to map completion item".to_string(),
69 ));
70 }
71
72 Ok(results[0].clone())
73 }
74}
75
76impl Default for CompletionMapper {
77 fn default() -> Self {
78 Self::new()
79 }
80}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85 use std::collections::HashMap;
86
87 #[test]
88 fn test_map_completion_response() {
89 let mapper = CompletionMapper::new();
90 let response = serde_json::json!({
91 "result": {
92 "items": [
93 {
94 "label": "foo",
95 "kind": 12,
96 "detail": "function",
97 "documentation": "A foo function"
98 },
99 {
100 "label": "bar",
101 "kind": 13,
102 "detail": "variable",
103 "documentation": "A bar variable"
104 }
105 ]
106 }
107 });
108
109 let mut field_mappings = HashMap::new();
110 field_mappings.insert("label".to_string(), "$.label".to_string());
111 field_mappings.insert("kind".to_string(), "$.kind".to_string());
112 field_mappings.insert("detail".to_string(), "$.detail".to_string());
113
114 let rules = CompletionMappingRules {
115 items_path: "$.result.items".to_string(),
116 field_mappings,
117 transform: None,
118 };
119
120 let results = mapper.map(&response, &rules).unwrap();
121 assert_eq!(results.len(), 2);
122 assert_eq!(results[0]["label"], "foo");
123 assert_eq!(results[1]["label"], "bar");
124 }
125
126 #[test]
127 fn test_map_completion_with_custom_structure() {
128 let mapper = CompletionMapper::new();
129 let response = serde_json::json!({
130 "completions": [
131 {"name": "foo", "type": "function"},
132 {"name": "bar", "type": "variable"}
133 ]
134 });
135
136 let mut field_mappings = HashMap::new();
137 field_mappings.insert("label".to_string(), "$.name".to_string());
138 field_mappings.insert("kind".to_string(), "$.type".to_string());
139
140 let rules = CompletionMappingRules {
141 items_path: "$.completions".to_string(),
142 field_mappings,
143 transform: None,
144 };
145
146 let results = mapper.map(&response, &rules).unwrap();
147 assert_eq!(results.len(), 2);
148 assert_eq!(results[0]["label"], "foo");
149 assert_eq!(results[0]["kind"], "function");
150 }
151
152 #[test]
153 fn test_map_single_item() {
154 let mapper = CompletionMapper::new();
155 let item = serde_json::json!({
156 "label": "test",
157 "kind": 12,
158 "detail": "test function"
159 });
160
161 let mut field_mappings = HashMap::new();
162 field_mappings.insert("label".to_string(), "$.label".to_string());
163 field_mappings.insert("kind".to_string(), "$.kind".to_string());
164
165 let rules = CompletionMappingRules {
166 items_path: "$.result.items".to_string(),
167 field_mappings,
168 transform: None,
169 };
170
171 let result = mapper.map_item(&item, &rules).unwrap();
172 assert_eq!(result["label"], "test");
173 assert_eq!(result["kind"], 12);
174 }
175
176 #[test]
177 fn test_map_empty_response() {
178 let mapper = CompletionMapper::new();
179 let response = serde_json::json!({
180 "result": {
181 "items": []
182 }
183 });
184
185 let field_mappings = HashMap::new();
186 let rules = CompletionMappingRules {
187 items_path: "$.result.items".to_string(),
188 field_mappings,
189 transform: None,
190 };
191
192 let results = mapper.map(&response, &rules).unwrap();
193 assert_eq!(results.len(), 0);
194 }
195}