perl_diagnostics/catalog/
mod.rs1use crate::codes::DiagnosticCode;
8use serde_json::{Value, json};
9
10pub struct DiagnosticMeta {
12 pub code: Value,
14 pub desc: Option<Value>,
16 pub hint: Option<&'static str>,
20}
21
22impl Default for DiagnosticMeta {
23 fn default() -> Self {
24 Self { code: json!("PL001"), desc: None, hint: None }
25 }
26}
27
28impl DiagnosticMeta {
29 fn from_code(code: DiagnosticCode) -> Self {
30 Self {
31 code: json!(code.as_str()),
32 desc: code.documentation_url().map(|url| json!({ "href": url })),
33 hint: code.context_hint(),
34 }
35 }
36}
37
38#[must_use]
40pub fn diagnostic_meta(code: DiagnosticCode) -> DiagnosticMeta {
41 DiagnosticMeta::from_code(code)
42}
43
44#[must_use]
46pub fn parse_error() -> DiagnosticMeta {
47 diagnostic_meta(DiagnosticCode::ParseError)
48}
49
50#[must_use]
52pub fn syntax_error() -> DiagnosticMeta {
53 diagnostic_meta(DiagnosticCode::SyntaxError)
54}
55
56#[must_use]
58pub fn unexpected_eof() -> DiagnosticMeta {
59 diagnostic_meta(DiagnosticCode::UnexpectedEof)
60}
61
62#[must_use]
64pub fn missing_strict() -> DiagnosticMeta {
65 diagnostic_meta(DiagnosticCode::MissingStrict)
66}
67
68#[must_use]
70pub fn missing_warnings() -> DiagnosticMeta {
71 diagnostic_meta(DiagnosticCode::MissingWarnings)
72}
73
74#[must_use]
76pub fn unused_var() -> DiagnosticMeta {
77 diagnostic_meta(DiagnosticCode::UnusedVariable)
78}
79
80#[must_use]
82pub fn undefined_var() -> DiagnosticMeta {
83 diagnostic_meta(DiagnosticCode::UndefinedVariable)
84}
85
86#[must_use]
88pub fn missing_package_declaration() -> DiagnosticMeta {
89 diagnostic_meta(DiagnosticCode::MissingPackageDeclaration)
90}
91
92#[must_use]
94pub fn duplicate_package() -> DiagnosticMeta {
95 diagnostic_meta(DiagnosticCode::DuplicatePackage)
96}
97
98#[must_use]
100pub fn duplicate_sub() -> DiagnosticMeta {
101 diagnostic_meta(DiagnosticCode::DuplicateSubroutine)
102}
103
104#[must_use]
106pub fn missing_return() -> DiagnosticMeta {
107 diagnostic_meta(DiagnosticCode::MissingReturn)
108}
109
110#[must_use]
112pub fn bareword_filehandle() -> DiagnosticMeta {
113 diagnostic_meta(DiagnosticCode::BarewordFilehandle)
114}
115
116#[must_use]
118pub fn two_arg_open() -> DiagnosticMeta {
119 diagnostic_meta(DiagnosticCode::TwoArgOpen)
120}
121
122#[must_use]
124pub fn implicit_return() -> DiagnosticMeta {
125 diagnostic_meta(DiagnosticCode::ImplicitReturn)
126}
127
128#[must_use]
130pub fn eval_error_flow() -> DiagnosticMeta {
131 diagnostic_meta(DiagnosticCode::EvalErrorFlow)
132}
133
134#[must_use]
136pub fn critic_severity_5() -> DiagnosticMeta {
137 diagnostic_meta(DiagnosticCode::CriticSeverity5)
138}
139
140#[must_use]
142pub fn critic_severity_4() -> DiagnosticMeta {
143 diagnostic_meta(DiagnosticCode::CriticSeverity4)
144}
145
146#[must_use]
148pub fn critic_severity_3() -> DiagnosticMeta {
149 diagnostic_meta(DiagnosticCode::CriticSeverity3)
150}
151
152#[must_use]
154pub fn critic_severity_2() -> DiagnosticMeta {
155 diagnostic_meta(DiagnosticCode::CriticSeverity2)
156}
157
158#[must_use]
160pub fn critic_severity_1() -> DiagnosticMeta {
161 diagnostic_meta(DiagnosticCode::CriticSeverity1)
162}
163
164#[must_use]
166pub fn from_message(msg: &str) -> Option<DiagnosticMeta> {
167 DiagnosticCode::from_message(msg).map(diagnostic_meta)
168}
169
170#[cfg(test)]
171mod tests {
172 use super::{eval_error_flow, from_message, parse_error};
173
174 #[test]
175 fn parse_error_includes_stable_code_and_docs_url() {
176 let meta = parse_error();
177 assert_eq!(meta.code, "PL001");
178 assert_eq!(
179 meta.desc,
180 Some(serde_json::json!({ "href": "https://docs.perl-lsp.org/errors/PL001" }))
181 );
182 }
183
184 #[test]
185 fn critic_codes_have_no_docs_url() {
186 let meta = super::critic_severity_1();
187 assert_eq!(meta.code, "PC001");
188 assert!(meta.desc.is_none());
189 }
190
191 #[test]
192 fn eval_error_flow_has_stable_code_and_docs_url() {
193 let meta = eval_error_flow();
194 assert_eq!(meta.code, "PL407");
195 assert_eq!(
196 meta.desc,
197 Some(serde_json::json!({ "href": "https://docs.perl-lsp.org/errors/PL407" }))
198 );
199 }
200
201 #[test]
202 fn message_inference_is_case_insensitive() {
203 let meta = from_message("Missing USE STRICT pragma");
204 assert!(meta.is_some());
205 assert_eq!(meta.as_ref().map(|m| &m.code), Some(&serde_json::json!("PL100")));
206 }
207}