-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.ts
170 lines (151 loc) · 4.59 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
import fs from "fs";
import path from "path";
import https from "https";
import url from "url";
interface LinkCheckResult {
url: string;
status: number | "skipped" | "error";
message?: string;
}
interface StatusCounts {
"200": number;
"404": number;
error: number;
skipped: number;
other: number;
}
async function checkDeadLinksInMarkdownFile(filePath: string): Promise<void> {
// Function to read markdown content from file
function readMarkdownFile(filePath: string): string {
try {
return fs.readFileSync(filePath, "utf8");
} catch (error) {
console.error(`Error reading file: ${(error as Error).message}`);
process.exit(1);
}
}
// Function to extract links from md file
function extractLinks(markdown: string): string[] {
const linkRegex = /\[([^\]]+)\]\(([^)]+)\)/g;
const links: string[] = [];
let match: RegExpExecArray | null;
while ((match = linkRegex.exec(markdown)) !== null) {
links.push(match[2]);
}
return links;
}
// Function to resolve relative URL
function resolveURL(base: string, relative: string): string {
if (relative.startsWith("http://") || relative.startsWith("https://")) {
return relative;
}
return url.resolve(base, relative);
}
// Function to check a single link
function checkLink(linkURL: string): Promise<LinkCheckResult> {
return new Promise((resolve) => {
if (!linkURL.startsWith("http://") && !linkURL.startsWith("https://")) {
resolve({
url: linkURL,
status: "skipped",
message: "Not an HTTP/HTTPS URL",
});
return;
}
https
.get(linkURL, (res) => {
resolve({
url: linkURL,
status: res.statusCode ?? 0,
});
})
.on("error", (e: Error) => {
resolve({
url: linkURL,
status: "error",
message: e.message,
});
});
});
}
// Function to creating a progress bar
function createProgressBar(
current: number,
total: number,
width: number = 50
): string {
const percentage = Math.round((current / total) * 100);
const filledWidth = Math.round((width * current) / total);
const bar = "=".repeat(filledWidth) + " ".repeat(width - filledWidth);
return `[${bar}] ${percentage}%`;
}
// Function to log check link result
function logLinkCheckResult(
number: number,
total: number,
result: LinkCheckResult
): void {
console.log(`\nLink ${number}/${total}: ${result.url}`);
console.log(`Status: ${result.status}`);
if (result.message) {
console.log(`Message: ${result.message}`);
}
console.log(createProgressBar(number, total));
}
// Main function start here
const markdown = readMarkdownFile(filePath);
const fileDir = path.dirname(filePath);
const baseURL = `file://${fileDir}/`;
const links = extractLinks(markdown);
const resolvedLinks = links.map((link) => resolveURL(baseURL, link));
const totalLinks = resolvedLinks.length;
console.log(`Starting to check ${totalLinks} links...\n`);
const statusCounts: StatusCounts = {
"200": 0,
"404": 0,
error: 0,
skipped: 0,
other: 0,
};
const notFoundLinks: string[] = [];
for (let i = 0; i < resolvedLinks.length; i++) {
const link = resolvedLinks[i];
try {
const result = await checkLink(link);
// Update status count
if (result.status === 200) {
statusCounts["200"]++;
} else if (result.status === 404) {
statusCounts["404"]++;
notFoundLinks.push(result.url);
} else if (result.status === "error") {
statusCounts.error++;
} else if (result.status === "skipped") {
statusCounts.skipped++;
} else {
statusCounts.other++;
}
// Log all results, including 200 status
logLinkCheckResult(i + 1, totalLinks, result);
} catch (error) {
console.error("An error occurred:", error);
statusCounts.error++;
}
}
// Print summary
console.log("\nSummary:");
console.log(`Total links checked: ${totalLinks}`);
console.log(`OK (200): ${statusCounts["200"]}`);
console.log(`Not Found (404): ${statusCounts["404"]}`);
console.log(`Errors: ${statusCounts.error}`);
console.log(`Skipped: ${statusCounts.skipped}`);
console.log(`Other status codes: ${statusCounts.other}`);
// Print list of 404 links
if (notFoundLinks.length > 0) {
console.log("\nLinks returning 404 (Not Found):");
notFoundLinks.forEach((link, index) => {
console.log(`${index + 1}. ${link}`);
});
}
}
checkDeadLinksInMarkdownFile("file.md");