-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlinkCheck.ts
118 lines (102 loc) · 3.31 KB
/
linkCheck.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
import Bun from "bun";
const isTTY = process.stdout.isTTY ?? false;
class Log {
sleepCount = 25;
lineLength = 0;
async clearLine() {
if (isTTY) {
const sleepDuration = this.sleepCount * Math.ceil(this.lineLength / 1);
// process.stdout.clearLine(0);
// await sleep(sleepDuration);
process.stdout.cursorTo(0);
await sleep(sleepDuration);
}
}
async msg(msg: string) {
this.clearLine();
if (isTTY) {
process.stdout.write(msg);
} else {
console.log(msg);
}
this.lineLength = msg.length;
await sleep(this.sleepCount);
}
async next() {
if (isTTY) {
process.stdout.write("\n");
await sleep(this.sleepCount);
}
}
}
function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
const brokenLinks: Record<string, Array<{ url: string; error: Error }>> = {};
const log = new Log();
const glob = new Bun.Glob("**/*.md");
const contentPath = "./src/content";
for await (const filePath of glob.scan(contentPath)) {
const fullFilePath = [contentPath, filePath].join("/");
if (!isTTY) {
console.log();
}
console.log(`📔 Checking ${fullFilePath}`);
const record = Bun.file(fullFilePath);
await log.msg(`📖 Reading File`);
const contents = await record.text();
await log.msg(`🔍 Looking for Links`);
const links = Array.from(
contents.match(new RegExp(`(https?:)\\/{2}[^\\s\\'")]+`, "gi")) ?? []
).filter((link) => !link.includes("localhost") && !link.includes("site-containers"));
if (links.length > 0) {
for (const link of links) {
const url = new URL(link);
await log.msg(`🔄 ${isTTY ? url.origin : link}`);
if (!isTTY) {
console.log();
}
if (link) {
try {
await fetch(link, { signal: AbortSignal.timeout(5000) });
await log.msg(`✅ ${isTTY ? url.origin : link}`);
} catch (e) {
if (!brokenLinks[fullFilePath]) {
brokenLinks[fullFilePath] = [];
}
if (e instanceof Error) {
}
brokenLinks[fullFilePath].push({
url: link,
error: e instanceof Error ? e : new Error(String(e))
});
await log.msg(`❌ ${isTTY ? url.origin : link}`);
}
}
log.next();
}
} else {
log.msg(`✅ No Links`);
log.next();
}
log.next();
} // close each file path
if (Object.keys(brokenLinks).length > 0) {
console.log(``);
console.log(`Some Broken Links were found in the following files:`);
console.log(``);
for (const [filePath, links] of Object.entries(brokenLinks)) {
console.log(`📔 Broken Links in ${filePath}`);
for (const link of links) {
console.log(`❌ ${link.url}`);
console.error(link.error);
}
console.log(``);
}
process.exit(1);
}
console.log("");
console.log("✅ Work Complete!");
console.log("All links are resolving");
console.log("");
process.exit(0);