1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
4pub struct Symbol {
5 pub symbol_id: String,
6 pub file_id: String,
7 pub path: String,
8 pub language: String,
9 pub name: String,
10 pub kind: String,
11 pub signature: Option<String>,
12 pub doc_comment: Option<String>,
13 pub visibility: Option<String>,
14 pub parent_symbol_id: Option<String>,
15 pub start_line: usize,
16 pub start_column: usize,
17 pub end_line: usize,
18 pub end_column: usize,
19 pub start_byte: usize,
20 pub end_byte: usize,
21 pub body_start_line: Option<usize>,
22 pub body_start_column: Option<usize>,
23 pub body_end_line: Option<usize>,
24 pub body_end_column: Option<usize>,
25 pub body_start_byte: Option<usize>,
26 pub body_end_byte: Option<usize>,
27 pub body_hash: Option<String>,
28 pub semantic_group: Option<String>,
29 pub is_test: bool,
30 pub test_container: bool,
31}
32
33impl Symbol {
34 pub fn hidden_body_line_count(&self) -> Option<usize> {
36 match (self.body_start_line, self.body_end_line) {
37 (Some(start), Some(end)) if end >= start => Some(end - start + 1),
38 _ => None,
39 }
40 }
41}
42
43#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
44pub struct FileFact {
45 pub file_id: String,
46 pub path: String,
47 pub language: String,
48 pub content_hash: String,
49 pub content_bytes: i64,
50 pub line_count: Option<i64>,
51 pub indexed_at: String,
52}
53
54#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
55pub struct ReferenceSite {
56 pub from_symbol_name: String,
57 pub from_symbol_id: String,
58 pub to_symbol_name: String,
59 pub kind: String,
60 pub path: String,
61 pub start_line: Option<usize>,
62 pub start_column: Option<usize>,
63 #[serde(default, skip_serializing_if = "Option::is_none")]
64 pub occurrences: Option<usize>,
65 #[serde(default, skip_serializing_if = "Option::is_none")]
67 pub target: Option<String>,
68 #[serde(skip)]
70 pub enclosing_symbol_name: Option<String>,
71}
72
73#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)]
75#[serde(rename_all = "snake_case")]
76pub enum SiteLabel {
77 Proven,
78 Likely,
79 Unresolved,
80 Excluded,
81}
82
83impl SiteLabel {
84 pub const ALL: [SiteLabel; 4] = [
85 SiteLabel::Proven,
86 SiteLabel::Likely,
87 SiteLabel::Unresolved,
88 SiteLabel::Excluded,
89 ];
90
91 pub fn as_str(self) -> &'static str {
92 match self {
93 SiteLabel::Proven => "proven",
94 SiteLabel::Likely => "likely",
95 SiteLabel::Unresolved => "unresolved",
96 SiteLabel::Excluded => "excluded",
97 }
98 }
99
100 pub fn rank(self) -> usize {
102 match self {
103 SiteLabel::Proven => 0,
104 SiteLabel::Likely => 1,
105 SiteLabel::Unresolved => 2,
106 SiteLabel::Excluded => 3,
107 }
108 }
109}
110
111#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
114pub struct LabeledSite {
115 #[serde(flatten)]
116 pub site: ReferenceSite,
117 pub label: SiteLabel,
118 pub basis: String,
119 #[serde(default, skip_serializing_if = "Option::is_none")]
120 pub end_line: Option<usize>,
121 #[serde(default, skip_serializing_if = "Option::is_none")]
123 pub arg_count: Option<u32>,
124}
125
126#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
128pub struct TextOnlyLines {
129 pub path: String,
130 pub lines: Vec<usize>,
131}
132
133#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
135pub struct TextScanSummary {
136 pub files_scanned: usize,
137 pub files_total: usize,
138 pub complete: bool,
139 pub elapsed_ms: u64,
140 #[serde(default, skip_serializing_if = "Option::is_none")]
143 pub skipped: Option<String>,
144}
145
146#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
147pub struct ReferenceCounts {
148 pub sites: usize,
149 pub proven: usize,
150 pub likely: usize,
151 pub unresolved: usize,
152 pub excluded: usize,
153 pub text_lines: usize,
154 pub site_lines: usize,
155 pub definition_lines: usize,
156 pub import_lines: usize,
157 pub text_only_lines: usize,
158}
159
160#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
161pub struct ReferenceTarget {
162 pub symbol_id: String,
163 pub name: String,
164 pub display_name: String,
166 pub kind: String,
167 pub path: String,
168 pub line: usize,
169 pub definitions_with_name: usize,
170}
171
172#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
175pub struct OverrideRow {
176 pub symbol_id: String,
177 pub owner: String,
178 pub name: String,
179 pub path: String,
180 pub line: usize,
181}
182
183#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
185pub struct ConstructionSite {
186 pub path: String,
187 pub line: usize,
188}
189
190#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
193pub struct VariantUse {
194 pub caller: String,
195 pub caller_id: String,
196 pub path: String,
197 pub line: usize,
198 pub variants_used: usize,
199 pub variants_total: usize,
200}
201
202#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
206pub struct Registration {
207 pub pattern_id: String,
208 pub verb: Option<String>,
209 pub template: Option<String>,
210 pub path: String,
211 pub line: usize,
212 pub by_name: bool,
213}
214
215#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
219pub struct CallingTest {
220 pub symbol_id: String,
221 pub name: String,
222 pub path: String,
223 pub line: usize,
224 #[serde(default, skip_serializing_if = "Option::is_none")]
225 pub command: Option<String>,
226 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
228 pub name_only: bool,
229}
230
231#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
236pub struct ReferenceReport {
237 pub target: ReferenceTarget,
238 pub counts: ReferenceCounts,
239 pub sites: Vec<LabeledSite>,
240 pub text_only: Vec<TextOnlyLines>,
241 pub text_scan: TextScanSummary,
242 pub cannot_see: Vec<String>,
243 pub imports: Vec<(String, usize)>,
244 #[serde(default, skip_serializing_if = "Vec::is_empty")]
246 pub overrides: Vec<OverrideRow>,
247 #[serde(default, skip_serializing_if = "Vec::is_empty")]
249 pub overridden: Vec<OverrideRow>,
250 #[serde(default, skip_serializing_if = "Vec::is_empty")]
252 pub constructions: Vec<ConstructionSite>,
253 #[serde(default, skip_serializing_if = "Vec::is_empty")]
255 pub variant_uses: Vec<VariantUse>,
256 #[serde(default, skip_serializing_if = "Vec::is_empty")]
258 pub registrations: Vec<Registration>,
259 #[serde(default, skip_serializing_if = "Vec::is_empty")]
261 pub tests: Vec<CallingTest>,
262}
263
264pub(crate) fn has_generated_lambda_name(name: &str) -> bool {
265 name.strip_prefix("lambda_")
266 .is_some_and(|line| !line.is_empty() && line.bytes().all(|byte| byte.is_ascii_digit()))
267}
268
269pub(crate) fn is_generated_lambda_name(
270 name: &str,
271 language: &str,
272 kind: &str,
273 signature: Option<&str>,
274) -> bool {
275 has_generated_lambda_name(name)
276 && language == "python"
277 && kind == "function"
278 && signature.is_some_and(|signature| signature.starts_with("lambda"))
279}
280
281#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
282pub struct StructuralFact {
283 pub structural_fact_id: String,
284 pub path: String,
285 pub language: String,
286 pub pattern_id: String,
287 pub capture_name: String,
288 pub node_kind: String,
289 pub key: Option<String>,
290 pub metadata: Option<serde_json::Value>,
291 pub containing_symbol_name: Option<String>,
292 pub start_line: usize,
293 pub end_line: usize,
294 pub confidence: f64,
295}
296
297#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
298pub struct LiteralFact {
299 pub literal_id: String,
300 pub path: String,
301 pub literal_text: String,
302 pub kind: String,
303 pub carrier: Option<String>,
304 pub start_line: usize,
305 pub containing_symbol_name: Option<String>,
306}
307
308#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
309pub struct TypeFact {
310 pub type_fact_id: String,
311 pub symbol_id: String,
312 pub language: String,
313 pub resolved_type: String,
314 pub generic_params: Option<String>,
315}
316
317#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
318pub struct ContextSlice {
319 pub target_symbol: Symbol,
320 pub target_body: String,
321 pub callee_signatures: Vec<String>,
322 pub related_types: Vec<String>,
323 pub related_tests: Vec<Symbol>,
324}
325
326#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
329pub struct SymbolSearchResult {
330 pub symbol: Symbol,
331 pub score: f64,
332 pub snippet: Option<String>,
333 #[serde(default, skip_serializing_if = "Option::is_none")]
334 pub explain: Option<SearchExplain>,
335}
336
337#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
342pub struct SearchExplain {
343 pub bm25: Option<f64>,
344 pub branches: Vec<String>,
345 pub name_tier: String,
346 pub name_strength: u32,
347 pub terms: Vec<(String, String, f64)>,
348 pub term_score: f64,
349 #[serde(default)]
350 pub field_diversity_bonus: f64,
351 pub name_bonus: f64,
352 pub kind_prior: f64,
353 pub path_role: f64,
354 pub documentation: f64,
355 pub test_intent: f64,
356 #[serde(default)]
357 pub nested: f64,
358 pub word_weights: Vec<(String, f64)>,
359 pub candidates: usize,
360 pub rerank_us: u128,
361}
362
363#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
364pub struct BlastRadiusResult {
365 pub seed_type: String,
366 pub seeds: Vec<String>,
367 pub likely_tests: Vec<TestTarget>,
368 pub impacted_symbols: Vec<ImpactedSymbol>,
369 pub likely_tests_truncated: bool,
370 pub impacted_symbols_truncated: bool,
371 #[serde(default)]
372 pub traversal_ceiling_reached: bool,
373 #[serde(default)]
375 pub limit_at_maximum: bool,
376 #[serde(default)]
378 pub likely_tests_found: usize,
379 #[serde(default)]
381 pub impacted_symbols_found: usize,
382 #[serde(default)]
384 pub stopped_at_depth: Option<usize>,
385}
386
387#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
388pub struct TestTarget {
389 pub name: String,
390 pub path: String,
391 pub line: usize,
392 pub reason: String,
393}
394
395#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
396pub struct ImpactedSymbol {
397 pub name: String,
398 pub kind: String,
399 pub path: String,
400 pub line: usize,
401 pub depth: usize,
402 #[serde(skip)]
404 pub enclosing_symbol_name: Option<String>,
405}