@majordigital/create-acorn 1.6.5 → 1.6.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/create-acorn.mjs +1 -1
- package/package.json +1 -1
- package/template/scripts/check-links.mjs +16 -27
package/bin/create-acorn.mjs
CHANGED
|
@@ -118,7 +118,7 @@ async function setupPreDeploy() {
|
|
|
118
118
|
|
|
119
119
|
console.log('Installing pre-deploy tools (Lighthouse, Playwright, linkinator)...');
|
|
120
120
|
await runCommand('npm', ['install', '--save-dev', '--legacy-peer-deps',
|
|
121
|
-
'lighthouse', 'chrome-launcher', 'playwright', 'linkinator'
|
|
121
|
+
'lighthouse', 'chrome-launcher', 'playwright', 'linkinator@^7'
|
|
122
122
|
]);
|
|
123
123
|
console.log('');
|
|
124
124
|
|
package/package.json
CHANGED
|
@@ -28,30 +28,21 @@ const concurrency = isLocalhost ? 2 : 5;
|
|
|
28
28
|
|
|
29
29
|
// Support Netlify Basic Auth (password-protected preview deploys).
|
|
30
30
|
// Set NETLIFY_AUTH=user:password in your environment before running.
|
|
31
|
+
// NOTE: requires linkinator >=7 (the `headers` option is applied to every
|
|
32
|
+
// fetch). Credentials are sent via an Authorization header, not embedded in
|
|
33
|
+
// the URL — Node's fetch (undici) rejects URLs that contain credentials.
|
|
31
34
|
const netlifyAuth = process.env.NETLIFY_AUTH;
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const escapedHostname = hostname.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
36
|
-
|
|
37
|
-
// Rewrite every internal link to include credentials so all requests authenticate.
|
|
38
|
-
// Without this, links found in HTML use clean URLs and get 401.
|
|
39
|
-
const urlRewriteExpressions = netlifyAuth
|
|
40
|
-
? [{ pattern: new RegExp(`^${protocol}//${escapedHostname}`), replacement: `${protocol}//${netlifyAuth}@${hostname}` }]
|
|
41
|
-
: [];
|
|
42
|
-
|
|
43
|
-
const crawlUrl = netlifyAuth
|
|
44
|
-
? baseUrl.replace(/^(https?:\/\/)/, `$1${netlifyAuth}@`)
|
|
45
|
-
: baseUrl;
|
|
35
|
+
const headers = netlifyAuth
|
|
36
|
+
? { Authorization: `Basic ${Buffer.from(netlifyAuth).toString("base64")}` }
|
|
37
|
+
: {};
|
|
46
38
|
|
|
47
39
|
const checker = new LinkChecker();
|
|
48
40
|
|
|
49
41
|
checker.on("link", (result) => {
|
|
50
42
|
if (result.state === "BROKEN") {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
console.log(` BROKEN [${result.status}] ${url} (from ${parent})`);
|
|
43
|
+
console.log(
|
|
44
|
+
` BROKEN [${result.status}] ${result.url} (from ${result.parent})`,
|
|
45
|
+
);
|
|
55
46
|
}
|
|
56
47
|
});
|
|
57
48
|
|
|
@@ -61,14 +52,14 @@ console.log(`Concurrency: ${concurrency}`);
|
|
|
61
52
|
console.log("This may take several minutes...\n");
|
|
62
53
|
|
|
63
54
|
const result = await checker.check({
|
|
64
|
-
path:
|
|
55
|
+
path: baseUrl,
|
|
65
56
|
recurse: true,
|
|
66
57
|
concurrency,
|
|
67
58
|
timeout: 30000,
|
|
68
|
-
|
|
59
|
+
headers,
|
|
69
60
|
linksToSkip: [
|
|
70
|
-
// Skip
|
|
71
|
-
`^(?!
|
|
61
|
+
// Skip external links to avoid false positives from rate limiting
|
|
62
|
+
`^(?!(${baseUrl.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}))`,
|
|
72
63
|
// Skip multi-filter URLs — the filter UI generates combinatorial links
|
|
73
64
|
// (e.g. ?filter=a%2Cb%2Cc) that cause a crawl explosion. Not real links.
|
|
74
65
|
".*[?&]filter=.*%2C.*",
|
|
@@ -95,8 +86,6 @@ console.log(`OK: ${ok.length}`);
|
|
|
95
86
|
console.log(`Broken: ${broken.length}`);
|
|
96
87
|
console.log(`Skipped: ${skipped.length}`);
|
|
97
88
|
|
|
98
|
-
const stripAuth = (u) => u?.replace(/\/\/[^@]+@/, "//") ?? u;
|
|
99
|
-
|
|
100
89
|
let md = `## Broken Link Check\n\n`;
|
|
101
90
|
md += `Crawled: ${baseUrl}\n\n`;
|
|
102
91
|
md += `| Metric | Count |\n|--------|-------|\n`;
|
|
@@ -108,11 +97,11 @@ md += `| Skipped | ${skipped.length} |\n\n`;
|
|
|
108
97
|
if (broken.length > 0) {
|
|
109
98
|
const grouped = new Map();
|
|
110
99
|
for (const link of broken) {
|
|
111
|
-
const key =
|
|
100
|
+
const key = link.url;
|
|
112
101
|
if (!grouped.has(key)) {
|
|
113
|
-
grouped.set(key, { status: link.status, url:
|
|
102
|
+
grouped.set(key, { status: link.status, url: link.url, foundOn: new Set() });
|
|
114
103
|
}
|
|
115
|
-
grouped.get(key).foundOn.add(
|
|
104
|
+
grouped.get(key).foundOn.add(link.parent);
|
|
116
105
|
}
|
|
117
106
|
|
|
118
107
|
md += `### Broken Links (${grouped.size} unique)\n\n`;
|