use crate::concern::lint::Level;
use crate::concern::lint::TagSet;
use crate::concern::Code;
use crate::display;
use crate::file::Location;
mod builder;
pub use builder::Builder;
use nonempty::NonEmpty;
use serde::Deserialize;
use serde::Serialize;
#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub struct Warning {
code: Code,
level: Level,
tags: TagSet,
locations: NonEmpty<Location>,
subject: String,
body: String,
fix: Option<String>,
}
impl Warning {
pub fn code(&self) -> &Code {
&self.code
}
pub fn level(&self) -> &Level {
&self.level
}
pub fn tags(&self) -> &TagSet {
&self.tags
}
pub fn locations(&self) -> &NonEmpty<Location> {
&self.locations
}
pub fn subject(&self) -> &str {
self.subject.as_ref()
}
pub fn body(&self) -> &str {
self.body.as_str()
}
pub fn fix(&self) -> Option<&str> {
self.fix.as_deref()
}
pub fn display(&self, f: &mut impl std::fmt::Write, mode: display::Mode) -> std::fmt::Result {
match mode {
display::Mode::OneLine => display_one_line(self, f),
display::Mode::Full => display_full(self, f),
}
}
}
fn display_one_line(warning: &Warning, f: &mut impl std::fmt::Write) -> std::fmt::Result {
write!(
f,
"[{}::{}::{:?}] {}",
warning.code, warning.tags, warning.level, warning.subject
)?;
let locations = warning
.locations
.iter()
.flat_map(|location| location.to_string())
.collect::<Vec<_>>();
if !locations.is_empty() {
write!(f, " ({})", locations.join(", "))?;
}
Ok(())
}
fn display_full(warning: &Warning, f: &mut impl std::fmt::Write) -> std::fmt::Result {
display_one_line(warning, f)?;
write!(f, "\n\n{}", warning.body)?;
if let Some(fix) = warning.fix() {
write!(f, "\n\nTo fix this warning, {}", fix.to_ascii_lowercase())?;
}
Ok(())
}
impl std::fmt::Display for Warning {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.display(f, display::Mode::OneLine)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::concern::lint::Tag;
#[test]
fn display() -> Result<(), Box<dyn std::error::Error>> {
let code = Code::try_new(crate::concern::code::Kind::Warning, crate::Version::V1, 1)?;
let warning = Builder::default()
.code(code)
.level(Level::Medium)
.tags(TagSet::new(&[Tag::Style]))
.push_location(Location::Unplaced)
.subject("Hello, world!")
.body("A body.")
.fix("How to fix the issue.")
.try_build()?;
assert_eq!(
warning.to_string(),
"[v1::W001::[Style]::Medium] Hello, world!"
);
Ok(())
}
}