-
Notifications
You must be signed in to change notification settings - Fork 196
/
Copy pathcheck-redirects.ts
124 lines (113 loc) · 3.19 KB
/
check-redirects.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
/**
* @license
* Copyright 2021 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
import * as pathLib from 'path';
import * as fs from 'fs/promises';
import ansi from 'ansi-escape-sequences';
import fetch from 'node-fetch';
import {pageRedirects} from 'lit-dev-server/redirects.js';
import {fileURLToPath} from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = pathLib.dirname(__filename);
const {red, green, yellow, bold, reset} = ansi.style;
const OK = Symbol();
type ErrorMessage = string;
const isAbsoluteUrl = (str: string) => {
try {
new URL(str);
return true;
} catch {
return false;
}
};
const trimTrailingSlash = (str: string) =>
str.endsWith('/') ? str.slice(0, str.length - 1) : str;
const siteOutputDir = pathLib.resolve(
__dirname,
'../',
'../',
'lit-dev-content',
'_site'
);
const checkRedirect = async (
redirect: string
): Promise<ErrorMessage | typeof OK> => {
if (isAbsoluteUrl(redirect)) {
// Remote URLs.
let res;
try {
res = await fetch(redirect);
} catch (e) {
return `Fetch error: ${(e as Error).message}`;
}
if (res.status !== 200) {
return `HTTP ${res.status} error`;
}
} else {
// Local paths. A bit hacky, but since we know how Eleventy works, we don't
// need to actually run the server, we can just look directly in the built
// HTML output directory.
const {pathname, hash} = new URL(redirect, 'http://lit.dev');
const diskPath = pathLib.relative(
process.cwd(),
pathLib.join(siteOutputDir, trimTrailingSlash(pathname), 'index.html')
);
let data;
try {
data = await fs.readFile(diskPath, {encoding: 'utf8'});
} catch {
return `Could not find file matching path ${pathname}
Searched for file ${diskPath}`;
}
if (hash) {
// Another hack. Just do a regexp search for e.g. id="somesection" instead
// of DOM parsing. Should be good enough, especially given how regular our
// Markdown generated HTML is.
const idAttrRegExp = new RegExp(`\\sid=["']?${hash.slice(1)}["']?[\\s>]`);
if (data.match(idAttrRegExp) === null) {
return `Could not find section matching hash ${hash}.
Searched in file ${diskPath}`;
}
}
}
return OK;
};
const checkAllRedirects = async () => {
console.log('==========================');
console.log('Checking lit.dev redirects');
console.log('==========================');
console.log();
let fail = false;
const promises = [];
for (const [from, to] of pageRedirects) {
promises.push(
(async () => {
const result = await checkRedirect(to);
if (result === OK) {
console.log(`${bold + green}OK${reset} ${from} -> ${to}`);
} else {
console.log();
console.log(
`${bold + red}BROKEN REDIRECT${reset} ${from} -> ${
yellow + to + reset
}`
);
console.log(result);
console.log();
fail = true;
}
})()
);
}
await Promise.all(promises);
console.log();
if (fail) {
console.log('Redirects were broken!');
process.exit(1);
} else {
console.error('All redirects OK!');
}
};
checkAllRedirects();