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 Invalid(String),
53}
54
55impl LinkStatus {
56 pub fn is_broken(&self) -> bool {
57 match self {
58 LinkStatus::Local(local_link_status) => match local_link_status {
59 LocalLinkStatus::Valid => false,
60 _ => true,
61 },
62 LinkStatus::Remote(remote_link_status) => match remote_link_status {
63 RemoteLinkStatus::Reachable => false,
64 RemoteLinkStatus::Concern(_) => true, _ => true,
66 },
67 _ => true,
68 }
69 }
70}
71
72impl fmt::Display for LinkStatus {
73 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74 match self {
75 LinkStatus::Local(status) => fmt::Display::fmt(status, f),
76 LinkStatus::Remote(status) => fmt::Display::fmt(status, f),
77 LinkStatus::Invalid(err) => fmt::Display::fmt(err, f),
78 }
79 }
80}
81
82#[derive(Debug, Clone, PartialEq, Eq)]
83pub struct LinkCheckResult {
84 pub source_file: PathBuf,
85 pub raw_link: String,
86 pub status: LinkStatus,
87}
88
89pub struct MarkdownCheckResultFormatter<'a> {
90 result: &'a MarkdownCheckResult,
91 show_valid: bool,
92}
93
94impl MarkdownCheckResult {
95 pub fn display_with_config(&self, show_valid: bool) -> MarkdownCheckResultFormatter<'_> {
96 MarkdownCheckResultFormatter {
97 result: self,
98 show_valid,
99 }
100 }
101}
102
103#[derive(Debug)]
104pub struct MarkdownCheckResult {
105 pub success: bool,
106 pub checks: Vec<LinkCheckResult>,
107}
108
109impl<'a> fmt::Display for MarkdownCheckResultFormatter<'a> {
110 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
111 if self.result.success {
112 for check in &self.result.checks {
113 match &check.status {
114 checker::LinkStatus::Local(LocalLinkStatus::Valid) if self.show_valid => {
115 write!(
116 f,
117 "{} Valid local link {} at {}\n",
118 "OK".green().bold(),
119 check.raw_link.cyan(),
120 check.source_file.to_string_lossy().green(),
121 )?;
122 }
123 checker::LinkStatus::Local(status) if *status != LocalLinkStatus::Valid => {
124 write!(
125 f,
126 "{} Faulty local link {} at {} | {}\n",
127 "FAIL".red().bold(),
128 check.raw_link.cyan(),
129 check.source_file.to_string_lossy().green(),
130 check.status
131 )?;
132 }
133 checker::LinkStatus::Remote(RemoteLinkStatus::Concern(_))
134 | checker::LinkStatus::Remote(RemoteLinkStatus::Invalid(_)) => {
135 write!(
136 f,
137 "{} Faulty remote URL {} at {} | {}\n",
138 "FAIL".red().bold(),
139 check.raw_link.cyan(),
140 check.source_file.to_string_lossy().green(),
141 check.status
142 )?;
143 }
144 checker::LinkStatus::Invalid(err) => {
145 write!(
146 f,
147 "{} Invalid URL {} at {} | {}\n",
148 "FAIL".red().bold(),
149 check.raw_link.cyan(),
150 check.source_file.to_string_lossy().green(),
151 err
152 )?;
153 }
154 _ => {}
155 }
156 }
157 } else {
158 write!(
159 f,
160 "{} Failed to locate/parse markdown file",
161 "FAIL".red().bold()
162 )?;
163 }
164 Ok(())
165 }
166}
167
168pub mod invalid;
169pub mod local;
170pub mod remote;