forked from pklaschka/ssblc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
executable file
·117 lines (99 loc) · 4.21 KB
/
index.js
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
#!/usr/bin/env node
const puppeteer = require('puppeteer');
const fs = require('fs');
const path = require('path');
const process = require('process');
const url = require('url');
const express = require('express');
const packageInfo = require('./package');
let dir = path.resolve(__dirname, process.argv[2] || process.cwd()); // Docsify directory
if (process.argv[2] === '-h' || process.argv[2] === '--help') {
console.log('ssblc: Static Site Broken Link Checker');
console.log('A broken-link checker for static sites, like the ones generated with docsify');
console.log();
console.log('Usage:');
console.log('ssblc [directory]\tChecks the static site in the directory, CWD if none is specified');
console.log('-h --help\tDisplays help');
console.log('-v --version\tPrint version number');
process.exit(0);
} else if (process.argv[2] === '-v' || process.argv[2] === '--version') {
console.log(`${packageInfo.name} v${packageInfo.version}`);
console.log(`by ${packageInfo.author}`);
} else {
let found = 0;
let checked = 0;
let foundLinks = ['http://localhost:3000/'];
let checkedLinks = [];
let unfoundLinks = [];
if (fs.existsSync(dir) && fs.lstatSync(dir).isDirectory()) {
const app = express();
app.use(express.static(dir));
/**
* Checks the links
* @returns {Promise<void>}
*/
const action = async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setCacheEnabled(false);
let link;
page.on("response", response => {
const request = response.request();
const url = request.url();
if (url === link && response.status() > 399) {
console.error("request failed url:", url);
unfoundLinks.push(url);
} else if (response.status() > 399 && url.endsWith('.md') && !url.endsWith('_sidebar.md')) {
// Docsify
console.error("request failed url:", url);
unfoundLinks.push(url);
}
});
for (link = foundLinks.pop(); link; link = foundLinks.pop()) {
checked++;
checkedLinks.push(link);
console.log(`${checked - 1}/${found}\t Checking link: `, link);
await page.goto(link);
await page.waitForTimeout(100);
const content = await page.content();
if (link.startsWith('http://localhost:3000')) {
const newLinks = Array.from(
content.matchAll(/href="([^"]*)"/g),
m => m[1]
).map(nlink => url.resolve(link, nlink))
.filter(nlink => !checkedLinks.includes(nlink))
.filter(nlink => !foundLinks.includes(nlink)
)
.filter(nlink => !nlink.startsWith('mailto:'))
.filter(nlink => !nlink.startsWith('tel:'));
foundLinks.push(...newLinks);
found += newLinks.length;
}
}
await page.close();
await browser.close();
};
const runServer = async () => {
const server = app.listen(3000);
console.log('Running at http://localhost:3000\n');
try {
await action();
server.close();
if (unfoundLinks.length > 0) {
console.warn('\nBroken links were detected:');
console.log(unfoundLinks.reduce((previousValue, currentValue) => previousValue + '- ' + currentValue + '\n', ''));
process.exit(1);
} else {
console.info('All checks passed, no broken links detected...');
process.exit(0);
}
} catch (e) {
console.error(`Something didn't quite work as expected: ${e.message}`);
server.close(() => {
process.exit(1);
});
}
};
runServer();
}
}