use crate::codes::DiagnosticCode;
use serde_json::{Value, json};
pub struct DiagnosticMeta {
pub code: Value,
pub desc: Option<Value>,
pub hint: Option<&'static str>,
}
impl Default for DiagnosticMeta {
fn default() -> Self {
Self { code: json!("PL001"), desc: None, hint: None }
}
}
impl DiagnosticMeta {
fn from_code(code: DiagnosticCode) -> Self {
Self {
code: json!(code.as_str()),
desc: code.documentation_url().map(|url| json!({ "href": url })),
hint: code.context_hint(),
}
}
}
#[must_use]
pub fn diagnostic_meta(code: DiagnosticCode) -> DiagnosticMeta {
DiagnosticMeta::from_code(code)
}
#[must_use]
pub fn parse_error() -> DiagnosticMeta {
diagnostic_meta(DiagnosticCode::ParseError)
}
#[must_use]
pub fn syntax_error() -> DiagnosticMeta {
diagnostic_meta(DiagnosticCode::SyntaxError)
}
#[must_use]
pub fn unexpected_eof() -> DiagnosticMeta {
diagnostic_meta(DiagnosticCode::UnexpectedEof)
}
#[must_use]
pub fn missing_strict() -> DiagnosticMeta {
diagnostic_meta(DiagnosticCode::MissingStrict)
}
#[must_use]
pub fn missing_warnings() -> DiagnosticMeta {
diagnostic_meta(DiagnosticCode::MissingWarnings)
}
#[must_use]
pub fn unused_var() -> DiagnosticMeta {
diagnostic_meta(DiagnosticCode::UnusedVariable)
}
#[must_use]
pub fn undefined_var() -> DiagnosticMeta {
diagnostic_meta(DiagnosticCode::UndefinedVariable)
}
#[must_use]
pub fn missing_package_declaration() -> DiagnosticMeta {
diagnostic_meta(DiagnosticCode::MissingPackageDeclaration)
}
#[must_use]
pub fn duplicate_package() -> DiagnosticMeta {
diagnostic_meta(DiagnosticCode::DuplicatePackage)
}
#[must_use]
pub fn duplicate_sub() -> DiagnosticMeta {
diagnostic_meta(DiagnosticCode::DuplicateSubroutine)
}
#[must_use]
pub fn missing_return() -> DiagnosticMeta {
diagnostic_meta(DiagnosticCode::MissingReturn)
}
#[must_use]
pub fn bareword_filehandle() -> DiagnosticMeta {
diagnostic_meta(DiagnosticCode::BarewordFilehandle)
}
#[must_use]
pub fn two_arg_open() -> DiagnosticMeta {
diagnostic_meta(DiagnosticCode::TwoArgOpen)
}
#[must_use]
pub fn implicit_return() -> DiagnosticMeta {
diagnostic_meta(DiagnosticCode::ImplicitReturn)
}
#[must_use]
pub fn eval_error_flow() -> DiagnosticMeta {
diagnostic_meta(DiagnosticCode::EvalErrorFlow)
}
#[must_use]
pub fn critic_severity_5() -> DiagnosticMeta {
diagnostic_meta(DiagnosticCode::CriticSeverity5)
}
#[must_use]
pub fn critic_severity_4() -> DiagnosticMeta {
diagnostic_meta(DiagnosticCode::CriticSeverity4)
}
#[must_use]
pub fn critic_severity_3() -> DiagnosticMeta {
diagnostic_meta(DiagnosticCode::CriticSeverity3)
}
#[must_use]
pub fn critic_severity_2() -> DiagnosticMeta {
diagnostic_meta(DiagnosticCode::CriticSeverity2)
}
#[must_use]
pub fn critic_severity_1() -> DiagnosticMeta {
diagnostic_meta(DiagnosticCode::CriticSeverity1)
}
#[must_use]
pub fn from_message(msg: &str) -> Option<DiagnosticMeta> {
DiagnosticCode::from_message(msg).map(diagnostic_meta)
}
#[cfg(test)]
mod tests {
use super::{eval_error_flow, from_message, parse_error};
#[test]
fn parse_error_includes_stable_code_and_docs_url() {
let meta = parse_error();
assert_eq!(meta.code, "PL001");
assert_eq!(
meta.desc,
Some(serde_json::json!({ "href": "https://docs.perl-lsp.org/errors/PL001" }))
);
}
#[test]
fn critic_codes_have_no_docs_url() {
let meta = super::critic_severity_1();
assert_eq!(meta.code, "PC001");
assert!(meta.desc.is_none());
}
#[test]
fn eval_error_flow_has_stable_code_and_docs_url() {
let meta = eval_error_flow();
assert_eq!(meta.code, "PL407");
assert_eq!(
meta.desc,
Some(serde_json::json!({ "href": "https://docs.perl-lsp.org/errors/PL407" }))
);
}
#[test]
fn message_inference_is_case_insensitive() {
let meta = from_message("Missing USE STRICT pragma");
assert!(meta.is_some());
assert_eq!(meta.as_ref().map(|m| &m.code), Some(&serde_json::json!("PL100")));
}
}