1use core::fmt;
2use std::path::PathBuf;
3
4use colored::Colorize;
5
6use crate::checker;
7
8#[derive(Debug, Clone, PartialEq, Eq)]
9pub enum LocalLinkStatus {
10 Valid,
11 DoesNotExist,
12 InvalidPrefix,
13}
14
15impl fmt::Display for LocalLinkStatus {
16 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
17 match self {
18 LocalLinkStatus::Valid => write!(f, "The local link is valid"),
19 LocalLinkStatus::DoesNotExist => write!(f, "The local link does not exist"),
20 LocalLinkStatus::InvalidPrefix => {
21 write!(f, "The local link's path is malformatted")
22 }
23 }
24 }
25}
26
27#[derive(Debug, Clone, PartialEq, Eq)]
28pub enum RemoteLinkStatus {
29 Reachable, Concern(u16), Invalid(String), }
33
34impl fmt::Display for RemoteLinkStatus {
35 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36 match self {
37 Self::Concern(code) => {
38 write!(f, "The URL returned an unsuccessful status code: {}", code)
39 }
40 Self::Invalid(err) => {
41 write!(f, "The URL could not be reached: {}", err)
42 }
43 Self::Reachable => write!(f, "The URL returns 200 OK"),
44 }
45 }
46}
47
48#[derive(Debug, Clone, PartialEq, Eq)]
49pub enum LinkStatus {
50 Local(LocalLinkStatus),
51 Remote(RemoteLinkStatus),
52}
53
54impl LinkStatus {
55 pub fn is_broken(&self) -> bool {
56 match self {
57 LinkStatus::Local(local_link_status) => match local_link_status {
58 LocalLinkStatus::Valid => false,
59 _ => true,
60 },
61 LinkStatus::Remote(remote_link_status) => match remote_link_status {
62 RemoteLinkStatus::Reachable => false,
63 RemoteLinkStatus::Concern(_) => true, _ => true,
65 },
66 }
67 }
68}
69
70impl fmt::Display for LinkStatus {
71 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72 match self {
73 LinkStatus::Local(status) => fmt::Display::fmt(status, f),
74 LinkStatus::Remote(status) => fmt::Display::fmt(status, f),
75 }
76 }
77}
78
79#[derive(Debug, Clone, PartialEq, Eq)]
80pub struct LinkCheckResult {
81 pub source_file: PathBuf,
82 pub raw_link: String,
83 pub status: LinkStatus,
84}
85
86#[derive(Debug)]
87pub struct MarkdownCheckResult {
88 pub success: bool,
89 pub checks: Vec<LinkCheckResult>,
90}
91
92impl fmt::Display for MarkdownCheckResult {
93 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
94 if self.success {
95 for check in &self.checks {
96 match &check.status {
97 checker::LinkStatus::Local(status) if *status != LocalLinkStatus::Valid => {
98 write!(
99 f,
100 "{} Faulty local link {} at {} | {}\n",
101 "FAIL".red().bold(),
102 check.raw_link.cyan(),
103 check.source_file.to_string_lossy().green(),
104 check.status
105 )?;
106 }
107 checker::LinkStatus::Remote(RemoteLinkStatus::Concern(_))
108 | checker::LinkStatus::Remote(RemoteLinkStatus::Invalid(_)) => {
109 write!(
110 f,
111 "{} Faulty remote URL {} at {} | {}\n",
112 "FAIL".red().bold(),
113 check.raw_link.cyan(),
114 check.source_file.to_string_lossy().green(),
115 check.status
116 )?;
117 }
118 _ => {}
119 }
120 }
121 } else {
122 write!(
123 f,
124 "{} Failed to locate/parse markdown file",
125 "FAIL".red().bold()
126 )?;
127 }
128 Ok(())
129 }
130}
131
132pub mod local;
133pub mod remote;