perspt_coding/diag/
pyright.rs1use perspt_sdk::ResidualClass;
9
10use super::types::StructuredDiagnostic;
11
12pub const PARSER_ID: &str = "pyright-json-v1";
14
15fn classify_rule(rule: &str) -> ResidualClass {
16 match rule {
17 "reportMissingImports" | "reportMissingModuleSource" => ResidualClass::ImportGraph,
18 "reportUndefinedVariable" | "reportAttributeAccessIssue" => ResidualClass::SymbolMismatch,
19 "reportAssignmentType"
20 | "reportArgumentType"
21 | "reportReturnType"
22 | "reportGeneralTypeIssues"
23 | "reportOperatorIssue" => ResidualClass::Type,
24 _ => ResidualClass::Type,
25 }
26}
27
28pub fn parse(raw: &str) -> Vec<StructuredDiagnostic> {
30 let Ok(value) = serde_json::from_str::<serde_json::Value>(raw) else {
31 return Vec::new();
32 };
33 let Some(items) = value.get("generalDiagnostics").and_then(|d| d.as_array()) else {
34 return Vec::new();
35 };
36 items
37 .iter()
38 .filter(|item| item.get("severity").and_then(|s| s.as_str()) == Some("error"))
39 .map(|item| {
40 let rule = item
41 .get("rule")
42 .and_then(|rule| rule.as_str())
43 .map(str::to_string);
44 StructuredDiagnostic {
45 class: rule
46 .as_deref()
47 .map(classify_rule)
48 .unwrap_or(ResidualClass::Type),
49 code: rule,
50 message: item
51 .get("message")
52 .and_then(|m| m.as_str())
53 .unwrap_or_default()
54 .to_string(),
55 path: item
56 .get("file")
57 .and_then(|f| f.as_str())
58 .map(str::to_string),
59 line: item
60 .pointer("/range/start/line")
61 .and_then(|l| l.as_u64())
62 .and_then(|l| u32::try_from(l + 1).ok()),
63 column: item
64 .pointer("/range/start/character")
65 .and_then(|c| c.as_u64())
66 .and_then(|c| u32::try_from(c + 1).ok()),
67 primary: true,
68 suggestion: None,
69 }
70 })
71 .collect()
72}