@docusaurus/core 0.0.0-5797 → 0.0.0-5801
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.
|
@@ -11,10 +11,10 @@ export const createStatefulBrokenLinks = () => {
|
|
|
11
11
|
const allLinks = new Set();
|
|
12
12
|
return {
|
|
13
13
|
collectAnchor: (anchor) => {
|
|
14
|
-
allAnchors.add(anchor);
|
|
14
|
+
typeof anchor !== 'undefined' && allAnchors.add(anchor);
|
|
15
15
|
},
|
|
16
16
|
collectLink: (link) => {
|
|
17
|
-
allLinks.add(link);
|
|
17
|
+
typeof link !== 'undefined' && allLinks.add(link);
|
|
18
18
|
},
|
|
19
19
|
getCollectedAnchors: () => [...allAnchors],
|
|
20
20
|
getCollectedLinks: () => [...allLinks],
|
|
@@ -97,11 +97,16 @@ function Link({ isNavLink, to, href, activeClassName, isActive, 'data-noBrokenLi
|
|
|
97
97
|
}
|
|
98
98
|
};
|
|
99
99
|
}, [ioRef, targetLink, IOSupported, isInternal]);
|
|
100
|
+
// It is simple local anchor link targeting current page?
|
|
100
101
|
const isAnchorLink = targetLink?.startsWith('#') ?? false;
|
|
102
|
+
// Should we use a regular <a> tag instead of React-Router Link component?
|
|
101
103
|
const isRegularHtmlLink = !targetLink || !isInternal || isAnchorLink;
|
|
102
|
-
if (!
|
|
104
|
+
if (!noBrokenLinkCheck && (isAnchorLink || !isRegularHtmlLink)) {
|
|
103
105
|
brokenLinks.collectLink(targetLink);
|
|
104
106
|
}
|
|
107
|
+
if (props.id) {
|
|
108
|
+
brokenLinks.collectAnchor(props.id);
|
|
109
|
+
}
|
|
105
110
|
return isRegularHtmlLink ? (
|
|
106
111
|
// eslint-disable-next-line jsx-a11y/anchor-has-content, @docusaurus/no-html-links
|
|
107
112
|
<a ref={innerRef} href={targetLink} {...(targetLinkUnprefixed &&
|
|
@@ -14,15 +14,20 @@ const react_router_config_1 = require("react-router-config");
|
|
|
14
14
|
const utils_1 = require("@docusaurus/utils");
|
|
15
15
|
const utils_2 = require("./utils");
|
|
16
16
|
function getBrokenLinksForPage({ collectedLinks, pagePath, pageLinks, routes, }) {
|
|
17
|
-
|
|
17
|
+
const allCollectedPaths = new Set(Object.keys(collectedLinks));
|
|
18
18
|
function isPathBrokenLink(linkPath) {
|
|
19
|
-
const
|
|
19
|
+
const pathnames = [linkPath.pathname, decodeURI(linkPath.pathname)];
|
|
20
|
+
const matchedRoutes = pathnames
|
|
20
21
|
// @ts-expect-error: React router types RouteConfig with an actual React
|
|
21
22
|
// component, but we load route components with string paths.
|
|
22
23
|
// We don't actually access component here, so it's fine.
|
|
23
24
|
.map((l) => (0, react_router_config_1.matchRoutes)(routes, l))
|
|
24
25
|
.flat();
|
|
25
|
-
|
|
26
|
+
// The link path is broken if:
|
|
27
|
+
// - it doesn't match any route
|
|
28
|
+
// - it doesn't match any collected path
|
|
29
|
+
return (matchedRoutes.length === 0 &&
|
|
30
|
+
!pathnames.some((p) => allCollectedPaths.has(p)));
|
|
26
31
|
}
|
|
27
32
|
function isAnchorBrokenLink(linkPath) {
|
|
28
33
|
const { pathname, hash } = linkPath;
|
|
@@ -30,6 +35,12 @@ function getBrokenLinksForPage({ collectedLinks, pagePath, pageLinks, routes, })
|
|
|
30
35
|
if (hash === undefined) {
|
|
31
36
|
return false;
|
|
32
37
|
}
|
|
38
|
+
// Link has empty hash ("#", "/page#"...): we do not report it as broken
|
|
39
|
+
// Empty hashes are used for various weird reasons, by us and other users...
|
|
40
|
+
// See for example: https://github.com/facebook/docusaurus/pull/6003
|
|
41
|
+
if (hash === '') {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
33
44
|
const targetPage = collectedLinks[pathname] || collectedLinks[decodeURI(pathname)];
|
|
34
45
|
// link with anchor to a page that does not exist (or did not collect any
|
|
35
46
|
// link/anchor) is considered as a broken anchor
|
|
@@ -38,7 +49,8 @@ function getBrokenLinksForPage({ collectedLinks, pagePath, pageLinks, routes, })
|
|
|
38
49
|
}
|
|
39
50
|
// it's a broken anchor if the target page exists
|
|
40
51
|
// but the anchor does not exist on that page
|
|
41
|
-
|
|
52
|
+
const hashes = [hash, decodeURIComponent(hash)];
|
|
53
|
+
return !targetPage.anchors.some((anchor) => hashes.includes(anchor));
|
|
42
54
|
}
|
|
43
55
|
const brokenLinks = pageLinks.flatMap((link) => {
|
|
44
56
|
const linkPath = (0, utils_1.parseURLPath)(link, pagePath);
|
|
@@ -76,13 +88,22 @@ function filterIntermediateRoutes(routesInput) {
|
|
|
76
88
|
}
|
|
77
89
|
function getBrokenLinks({ collectedLinks, routes, }) {
|
|
78
90
|
const filteredRoutes = filterIntermediateRoutes(routes);
|
|
79
|
-
return lodash_1.default.mapValues(collectedLinks, (pageCollectedData, pagePath) =>
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
91
|
+
return lodash_1.default.mapValues(collectedLinks, (pageCollectedData, pagePath) => {
|
|
92
|
+
try {
|
|
93
|
+
return getBrokenLinksForPage({
|
|
94
|
+
collectedLinks,
|
|
95
|
+
pageLinks: pageCollectedData.links,
|
|
96
|
+
pageAnchors: pageCollectedData.anchors,
|
|
97
|
+
pagePath,
|
|
98
|
+
routes: filteredRoutes,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
catch (e) {
|
|
102
|
+
throw new Error(`Unable to get broken links for page ${pagePath}.`, {
|
|
103
|
+
cause: e,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
});
|
|
86
107
|
}
|
|
87
108
|
function brokenLinkMessage(brokenLink) {
|
|
88
109
|
const showResolvedLink = brokenLink.link !== brokenLink.resolvedLink;
|
|
@@ -179,11 +200,26 @@ function reportBrokenLinks({ brokenLinks, onBrokenLinks, onBrokenAnchors, }) {
|
|
|
179
200
|
logger_1.default.report(onBrokenAnchors)(anchorErrorMessage);
|
|
180
201
|
}
|
|
181
202
|
}
|
|
203
|
+
// Users might use the useBrokenLinks() API in weird unexpected ways
|
|
204
|
+
// JS users might call "collectLink(undefined)" for example
|
|
205
|
+
// TS users might call "collectAnchor('#hash')" with/without #
|
|
206
|
+
// We clean/normalize the collected data to avoid obscure errors being thrown
|
|
207
|
+
function normalizeCollectedLinks(collectedLinks) {
|
|
208
|
+
return lodash_1.default.mapValues(collectedLinks, (pageCollectedData) => ({
|
|
209
|
+
links: pageCollectedData.links.filter(lodash_1.default.isString),
|
|
210
|
+
anchors: pageCollectedData.anchors
|
|
211
|
+
.filter(lodash_1.default.isString)
|
|
212
|
+
.map((anchor) => (anchor.startsWith('#') ? anchor.slice(1) : anchor)),
|
|
213
|
+
}));
|
|
214
|
+
}
|
|
182
215
|
async function handleBrokenLinks({ collectedLinks, onBrokenLinks, onBrokenAnchors, routes, }) {
|
|
183
216
|
if (onBrokenLinks === 'ignore' && onBrokenAnchors === 'ignore') {
|
|
184
217
|
return;
|
|
185
218
|
}
|
|
186
|
-
const brokenLinks = getBrokenLinks({
|
|
219
|
+
const brokenLinks = getBrokenLinks({
|
|
220
|
+
routes,
|
|
221
|
+
collectedLinks: normalizeCollectedLinks(collectedLinks),
|
|
222
|
+
});
|
|
187
223
|
reportBrokenLinks({ brokenLinks, onBrokenLinks, onBrokenAnchors });
|
|
188
224
|
}
|
|
189
225
|
exports.handleBrokenLinks = handleBrokenLinks;
|
package/lib/server/routes.js
CHANGED
|
@@ -159,6 +159,14 @@ ${JSON.stringify(routeConfig)}`);
|
|
|
159
159
|
props,
|
|
160
160
|
});
|
|
161
161
|
}
|
|
162
|
+
/**
|
|
163
|
+
* Old stuff
|
|
164
|
+
* As far as I understand, this is what permits to SSG the 404.html file
|
|
165
|
+
* This is rendered through the catch-all ComponentCreator("*") route
|
|
166
|
+
* Note CDNs only understand the 404.html file by convention
|
|
167
|
+
* The extension probably permits to avoid emitting "/404/index.html"
|
|
168
|
+
*/
|
|
169
|
+
const NotFoundRoutePath = '/404.html';
|
|
162
170
|
/**
|
|
163
171
|
* Routes are prepared into three temp files:
|
|
164
172
|
*
|
|
@@ -175,7 +183,7 @@ function loadRoutes(routeConfigs, baseUrl, onDuplicateRoutes) {
|
|
|
175
183
|
routesConfig: '',
|
|
176
184
|
routesChunkNames: {},
|
|
177
185
|
registry: {},
|
|
178
|
-
routesPaths: [(0, utils_1.normalizeUrl)([baseUrl,
|
|
186
|
+
routesPaths: [(0, utils_1.normalizeUrl)([baseUrl, NotFoundRoutePath])],
|
|
179
187
|
};
|
|
180
188
|
// `genRouteCode` would mutate `res`
|
|
181
189
|
const routeConfigSerialized = routeConfigs
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@docusaurus/core",
|
|
3
3
|
"description": "Easy to Maintain Open Source Documentation Websites",
|
|
4
|
-
"version": "0.0.0-
|
|
4
|
+
"version": "0.0.0-5801",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|
|
7
7
|
"access": "public"
|
|
@@ -43,13 +43,13 @@
|
|
|
43
43
|
"@babel/runtime": "^7.22.6",
|
|
44
44
|
"@babel/runtime-corejs3": "^7.22.6",
|
|
45
45
|
"@babel/traverse": "^7.22.8",
|
|
46
|
-
"@docusaurus/cssnano-preset": "0.0.0-
|
|
47
|
-
"@docusaurus/logger": "0.0.0-
|
|
48
|
-
"@docusaurus/mdx-loader": "0.0.0-
|
|
46
|
+
"@docusaurus/cssnano-preset": "0.0.0-5801",
|
|
47
|
+
"@docusaurus/logger": "0.0.0-5801",
|
|
48
|
+
"@docusaurus/mdx-loader": "0.0.0-5801",
|
|
49
49
|
"@docusaurus/react-loadable": "5.5.2",
|
|
50
|
-
"@docusaurus/utils": "0.0.0-
|
|
51
|
-
"@docusaurus/utils-common": "0.0.0-
|
|
52
|
-
"@docusaurus/utils-validation": "0.0.0-
|
|
50
|
+
"@docusaurus/utils": "0.0.0-5801",
|
|
51
|
+
"@docusaurus/utils-common": "0.0.0-5801",
|
|
52
|
+
"@docusaurus/utils-validation": "0.0.0-5801",
|
|
53
53
|
"@slorber/static-site-generator-webpack-plugin": "^4.0.7",
|
|
54
54
|
"@svgr/webpack": "^6.5.1",
|
|
55
55
|
"autoprefixer": "^10.4.14",
|
|
@@ -104,8 +104,8 @@
|
|
|
104
104
|
"webpackbar": "^5.0.2"
|
|
105
105
|
},
|
|
106
106
|
"devDependencies": {
|
|
107
|
-
"@docusaurus/module-type-aliases": "0.0.0-
|
|
108
|
-
"@docusaurus/types": "0.0.0-
|
|
107
|
+
"@docusaurus/module-type-aliases": "0.0.0-5801",
|
|
108
|
+
"@docusaurus/types": "0.0.0-5801",
|
|
109
109
|
"@types/detect-port": "^1.3.3",
|
|
110
110
|
"@types/react-dom": "^18.2.7",
|
|
111
111
|
"@types/react-router-config": "^5.0.7",
|
|
@@ -124,5 +124,5 @@
|
|
|
124
124
|
"engines": {
|
|
125
125
|
"node": ">=18.0"
|
|
126
126
|
},
|
|
127
|
-
"gitHead": "
|
|
127
|
+
"gitHead": "44100c84778ec4735110e7a878269af287facaa7"
|
|
128
128
|
}
|