@docusaurus/core 2.0.0-beta.18 → 2.0.0-beta.19
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/beforeCli.mjs +12 -7
- package/bin/docusaurus.mjs +21 -72
- package/lib/client/.eslintrc.js +2 -3
- package/lib/client/App.d.ts +1 -1
- package/lib/client/App.js +9 -5
- package/lib/client/{baseUrlIssueBanner/BaseUrlIssueBanner.d.ts → BaseUrlIssueBanner/index.d.ts} +10 -5
- package/lib/client/{baseUrlIssueBanner/BaseUrlIssueBanner.js → BaseUrlIssueBanner/index.js} +14 -9
- package/lib/client/{baseUrlIssueBanner → BaseUrlIssueBanner}/styles.module.css +0 -0
- package/lib/client/ClientLifecyclesDispatcher.d.ts +16 -0
- package/lib/client/ClientLifecyclesDispatcher.js +34 -0
- package/lib/client/LinksCollector.js +1 -2
- package/lib/client/PendingNavigation.d.ts +8 -17
- package/lib/client/PendingNavigation.js +39 -70
- package/lib/client/clientEntry.js +1 -2
- package/lib/client/docusaurus.d.ts +5 -5
- package/lib/client/docusaurus.js +25 -29
- package/lib/client/exports/BrowserOnly.d.ts +3 -4
- package/lib/client/exports/BrowserOnly.js +1 -1
- package/lib/client/exports/ComponentCreator.js +51 -46
- package/lib/client/exports/ErrorBoundary.d.ts +2 -2
- package/lib/client/exports/Interpolate.js +16 -39
- package/lib/client/exports/Link.d.ts +3 -15
- package/lib/client/exports/Link.js +21 -26
- package/lib/client/exports/useBaseUrl.js +3 -9
- package/lib/client/exports/useGlobalData.d.ts +3 -3
- package/lib/client/exports/useGlobalData.js +5 -5
- package/lib/client/flat.d.ts +10 -2
- package/lib/client/flat.js +11 -3
- package/lib/client/normalizeLocation.js +14 -5
- package/lib/client/prefetch.js +7 -25
- package/lib/client/preload.d.ts +1 -3
- package/lib/client/preload.js +2 -2
- package/lib/client/routeContext.js +1 -1
- package/lib/client/serverEntry.js +12 -11
- package/lib/client/theme-fallback/Error/index.js +2 -0
- package/lib/client/theme-fallback/Loading/index.js +2 -0
- package/lib/client/theme-fallback/NotFound/index.js +2 -0
- package/lib/commands/build.d.ts +6 -2
- package/lib/commands/build.js +35 -15
- package/lib/commands/clear.d.ts +1 -1
- package/lib/commands/clear.js +3 -2
- package/lib/commands/deploy.d.ts +5 -2
- package/lib/commands/deploy.js +12 -9
- package/lib/commands/external.d.ts +1 -1
- package/lib/commands/external.js +5 -6
- package/lib/commands/serve.d.ts +7 -2
- package/lib/commands/serve.js +12 -12
- package/lib/commands/start.d.ts +8 -2
- package/lib/commands/start.js +14 -9
- package/lib/commands/swizzle/actions.d.ts +2 -2
- package/lib/commands/swizzle/actions.js +5 -4
- package/lib/commands/swizzle/common.d.ts +3 -3
- package/lib/commands/swizzle/components.js +41 -3
- package/lib/commands/swizzle/config.js +14 -11
- package/lib/commands/swizzle/context.js +6 -10
- package/lib/commands/swizzle/index.d.ts +2 -2
- package/lib/commands/swizzle/index.js +4 -3
- package/lib/commands/writeHeadingIds.d.ts +1 -1
- package/lib/commands/writeHeadingIds.js +5 -8
- package/lib/commands/writeTranslations.d.ts +3 -4
- package/lib/commands/writeTranslations.js +7 -9
- package/lib/index.d.ts +9 -10
- package/lib/index.js +18 -19
- package/lib/server/brokenLinks.js +1 -2
- package/lib/server/{client-modules/index.d.ts → clientModules.d.ts} +5 -1
- package/lib/server/{client-modules/index.js → clientModules.js} +6 -1
- package/lib/server/config.d.ts +5 -2
- package/lib/server/config.js +11 -6
- package/lib/server/configValidation.js +6 -5
- package/lib/server/getHostPort.d.ts +14 -0
- package/lib/{choosePort.js → server/getHostPort.js} +21 -35
- package/lib/server/htmlTags.d.ts +12 -0
- package/lib/server/htmlTags.js +62 -0
- package/lib/server/i18n.d.ts +2 -11
- package/lib/server/i18n.js +4 -19
- package/lib/server/index.d.ts +28 -13
- package/lib/server/index.js +42 -210
- package/lib/server/plugins/configs.d.ts +51 -0
- package/lib/server/plugins/configs.js +101 -0
- package/lib/server/plugins/index.d.ts +8 -7
- package/lib/server/plugins/index.js +59 -134
- package/lib/server/plugins/init.d.ts +6 -19
- package/lib/server/plugins/init.js +16 -68
- package/lib/server/{moduleShorthand.d.ts → plugins/moduleShorthand.d.ts} +0 -0
- package/lib/server/{moduleShorthand.js → plugins/moduleShorthand.js} +0 -0
- package/lib/server/plugins/pluginIds.d.ts +4 -0
- package/lib/server/plugins/pluginIds.js +4 -2
- package/lib/server/plugins/presets.d.ts +12 -0
- package/lib/server/{presets/index.js → plugins/presets.js} +14 -6
- package/lib/server/plugins/{applyRouteTrailingSlash.d.ts → routeConfig.d.ts} +3 -1
- package/lib/server/plugins/routeConfig.js +54 -0
- package/lib/server/plugins/synthetic.d.ts +20 -0
- package/lib/server/plugins/synthetic.js +112 -0
- package/lib/server/routes.d.ts +42 -8
- package/lib/server/routes.js +150 -92
- package/lib/server/{versions/index.d.ts → siteMetadata.d.ts} +5 -2
- package/lib/server/{versions/index.js → siteMetadata.js} +36 -3
- package/lib/server/translations/translations.d.ts +5 -13
- package/lib/server/translations/translations.js +5 -8
- package/lib/server/translations/translationsExtractor.d.ts +2 -4
- package/lib/webpack/aliases/index.d.ts +34 -0
- package/lib/webpack/aliases/index.js +106 -0
- package/lib/webpack/base.d.ts +0 -3
- package/lib/webpack/base.js +8 -25
- package/lib/webpack/client.js +1 -1
- package/lib/webpack/plugins/CleanWebpackPlugin.d.ts +2 -2
- package/lib/webpack/plugins/WaitPlugin.d.ts +2 -2
- package/lib/webpack/server.d.ts +2 -2
- package/lib/webpack/server.js +5 -3
- package/lib/webpack/utils.d.ts +3 -3
- package/lib/webpack/utils.js +3 -3
- package/package.json +33 -36
- package/lib/choosePort.d.ts +0 -11
- package/lib/client/client-lifecycles-dispatcher.d.ts +0 -9
- package/lib/client/client-lifecycles-dispatcher.js +0 -23
- package/lib/client/nprogress.css +0 -36
- package/lib/commands/commandUtils.d.ts +0 -9
- package/lib/commands/commandUtils.js +0 -21
- package/lib/server/duplicateRoutes.d.ts +0 -8
- package/lib/server/duplicateRoutes.js +0 -42
- package/lib/server/html-tags/htmlTags.d.ts +0 -7
- package/lib/server/html-tags/htmlTags.js +0 -38
- package/lib/server/html-tags/index.d.ts +0 -8
- package/lib/server/html-tags/index.js +0 -42
- package/lib/server/plugins/applyRouteTrailingSlash.js +0 -19
- package/lib/server/presets/index.d.ts +0 -11
- package/lib/server/themes/alias.d.ts +0 -9
- package/lib/server/themes/alias.js +0 -50
- package/lib/server/themes/index.d.ts +0 -12
- package/lib/server/themes/index.js +0 -47
package/lib/client/docusaurus.js
CHANGED
|
@@ -10,55 +10,51 @@ import routes from '@generated/routes';
|
|
|
10
10
|
import prefetchHelper from './prefetch';
|
|
11
11
|
import preloadHelper from './preload';
|
|
12
12
|
import flat from './flat';
|
|
13
|
-
const fetched =
|
|
14
|
-
const loaded =
|
|
13
|
+
const fetched = new Set();
|
|
14
|
+
const loaded = new Set();
|
|
15
15
|
// If user is on slow or constrained connection.
|
|
16
|
-
const isSlowConnection = () => navigator.connection?.effectiveType.includes('2g')
|
|
16
|
+
const isSlowConnection = () => navigator.connection?.effectiveType.includes('2g') ||
|
|
17
17
|
navigator.connection?.saveData;
|
|
18
|
-
const canPrefetch = (routePath) => !isSlowConnection() && !loaded
|
|
19
|
-
const canPreload = (routePath) => !isSlowConnection() && !loaded
|
|
18
|
+
const canPrefetch = (routePath) => !isSlowConnection() && !loaded.has(routePath) && !fetched.has(routePath);
|
|
19
|
+
const canPreload = (routePath) => !isSlowConnection() && !loaded.has(routePath);
|
|
20
|
+
const getChunkNamesToLoad = (path) => Object.entries(routesChunkNames)
|
|
21
|
+
.filter(
|
|
20
22
|
// Remove the last part containing the route hash
|
|
21
23
|
// input: /blog/2018/12/14/Happy-First-Birthday-Slash-fe9
|
|
22
24
|
// output: /blog/2018/12/14/Happy-First-Birthday-Slash
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
.filter(([routeNameWithHash]) => removeRouteNameHash(routeNameWithHash) === path)
|
|
26
|
-
.flatMap(([, routeChunks]) =>
|
|
27
|
-
// flat() is useful for nested chunk names, it's not like array.flat()
|
|
28
|
-
Object.values(flat(routeChunks)));
|
|
25
|
+
([routeNameWithHash]) => routeNameWithHash.replace(/-[^-]+$/, '') === path)
|
|
26
|
+
.flatMap(([, routeChunks]) => Object.values(flat(routeChunks)));
|
|
29
27
|
const docusaurus = {
|
|
30
|
-
prefetch
|
|
28
|
+
prefetch(routePath) {
|
|
31
29
|
if (!canPrefetch(routePath)) {
|
|
32
30
|
return false;
|
|
33
31
|
}
|
|
34
|
-
|
|
35
|
-
fetched[routePath] = true;
|
|
32
|
+
fetched.add(routePath);
|
|
36
33
|
// Find all webpack chunk names needed.
|
|
37
34
|
const matches = matchRoutes(routes, routePath);
|
|
38
35
|
const chunkNamesNeeded = matches.flatMap((match) => getChunkNamesToLoad(match.route.path));
|
|
39
36
|
// Prefetch all webpack chunk assets file needed.
|
|
40
|
-
chunkNamesNeeded.
|
|
41
|
-
// "__webpack_require__.gca" is
|
|
42
|
-
//
|
|
43
|
-
// it will return the URL for that chunk.
|
|
37
|
+
return Promise.all(chunkNamesNeeded.map((chunkName) => {
|
|
38
|
+
// "__webpack_require__.gca" is injected by ChunkAssetPlugin. Pass it
|
|
39
|
+
// the name of the chunk you want to load and it will return its URL.
|
|
44
40
|
// eslint-disable-next-line camelcase
|
|
45
41
|
const chunkAsset = __webpack_require__.gca(chunkName);
|
|
46
|
-
// In some cases, webpack might decide to optimize further
|
|
47
|
-
// chunk assets
|
|
48
|
-
//
|
|
42
|
+
// In some cases, webpack might decide to optimize further, leading to
|
|
43
|
+
// the chunk assets being merged to another chunk. In this case, we can
|
|
44
|
+
// safely filter it out and don't need to load it.
|
|
49
45
|
if (chunkAsset && !/undefined/.test(chunkAsset)) {
|
|
50
|
-
prefetchHelper(chunkAsset);
|
|
46
|
+
return prefetchHelper(chunkAsset);
|
|
51
47
|
}
|
|
52
|
-
|
|
53
|
-
|
|
48
|
+
return Promise.resolve();
|
|
49
|
+
}));
|
|
54
50
|
},
|
|
55
|
-
preload
|
|
51
|
+
preload(routePath) {
|
|
56
52
|
if (!canPreload(routePath)) {
|
|
57
53
|
return false;
|
|
58
54
|
}
|
|
59
|
-
loaded
|
|
60
|
-
preloadHelper(
|
|
61
|
-
return true;
|
|
55
|
+
loaded.add(routePath);
|
|
56
|
+
return preloadHelper(routePath);
|
|
62
57
|
},
|
|
63
58
|
};
|
|
64
|
-
|
|
59
|
+
// This object is directly mounted onto window, better freeze it
|
|
60
|
+
export default Object.freeze(docusaurus);
|
|
@@ -4,8 +4,7 @@
|
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
|
+
/// <reference types="@docusaurus/module-type-aliases" />
|
|
7
8
|
/// <reference types="react" />
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
fallback?: JSX.Element;
|
|
11
|
-
}): JSX.Element | null;
|
|
9
|
+
import type { Props } from '@docusaurus/BrowserOnly';
|
|
10
|
+
export default function BrowserOnly({ children, fallback, }: Props): JSX.Element | null;
|
|
@@ -16,7 +16,7 @@ export default function BrowserOnly({ children, fallback, }) {
|
|
|
16
16
|
throw new Error(`Docusaurus error: The children of <BrowserOnly> must be a "render function", e.g. <BrowserOnly>{() => <span>{window.location.href}</span>}</BrowserOnly>.
|
|
17
17
|
Current type: ${isValidElement(children) ? 'React element' : typeof children}`);
|
|
18
18
|
}
|
|
19
|
-
return <>{children()}</>;
|
|
19
|
+
return <>{children?.()}</>;
|
|
20
20
|
}
|
|
21
21
|
return fallback ?? null;
|
|
22
22
|
}
|
|
@@ -16,81 +16,86 @@ export default function ComponentCreator(path, hash) {
|
|
|
16
16
|
if (path === '*') {
|
|
17
17
|
return Loadable({
|
|
18
18
|
loading: Loading,
|
|
19
|
-
loader:
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
// Is there a better API for this?
|
|
23
|
-
<RouteContextProvider value={{ plugin: { name: 'native', id: 'default' } }}>
|
|
19
|
+
loader: () => import('@theme/NotFound').then(({ default: NotFound }) => (props) => (<RouteContextProvider
|
|
20
|
+
// Do we want a better name than native-default?
|
|
21
|
+
value={{ plugin: { name: 'native', id: 'default' } }}>
|
|
24
22
|
<NotFound {...props}/>
|
|
25
|
-
</RouteContextProvider>)
|
|
26
|
-
},
|
|
23
|
+
</RouteContextProvider>)),
|
|
27
24
|
});
|
|
28
25
|
}
|
|
29
|
-
const
|
|
30
|
-
const chunkNames = routesChunkNames[chunkNamesKey];
|
|
31
|
-
const optsModules = [];
|
|
32
|
-
const optsWebpack = [];
|
|
26
|
+
const chunkNames = routesChunkNames[`${path}-${hash}`];
|
|
33
27
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
- optsModules: ['./Pages.js', './doc1.md']
|
|
44
|
-
- optsWebpack: [
|
|
45
|
-
require.resolveWeak('./Pages.js'),
|
|
46
|
-
require.resolveWeak('./doc1.md'),
|
|
47
|
-
]
|
|
48
|
-
*/
|
|
28
|
+
const loader = {};
|
|
29
|
+
const modules = [];
|
|
30
|
+
const optsWebpack = [];
|
|
31
|
+
// A map from prop names to chunk names.
|
|
32
|
+
// e.g. Suppose the plugin added this as route:
|
|
33
|
+
// { __comp: "...", prop: { foo: "..." }, items: ["...", "..."] }
|
|
34
|
+
// It will become:
|
|
35
|
+
// { __comp: "...", "prop.foo": "...", "items.0": "...", "items.1": ... }
|
|
36
|
+
// Loadable.Map will _map_ over `loader` and load each key.
|
|
49
37
|
const flatChunkNames = flat(chunkNames);
|
|
50
|
-
Object.entries(flatChunkNames).forEach(([
|
|
38
|
+
Object.entries(flatChunkNames).forEach(([keyPath, chunkName]) => {
|
|
51
39
|
const chunkRegistry = registry[chunkName];
|
|
52
40
|
if (chunkRegistry) {
|
|
53
41
|
// eslint-disable-next-line prefer-destructuring
|
|
54
|
-
|
|
55
|
-
|
|
42
|
+
loader[keyPath] = chunkRegistry[0];
|
|
43
|
+
modules.push(chunkRegistry[1]);
|
|
56
44
|
optsWebpack.push(chunkRegistry[2]);
|
|
57
45
|
}
|
|
58
46
|
});
|
|
59
47
|
return Loadable.Map({
|
|
60
48
|
loading: Loading,
|
|
61
|
-
loader
|
|
62
|
-
modules
|
|
49
|
+
loader,
|
|
50
|
+
modules,
|
|
63
51
|
webpack: () => optsWebpack,
|
|
64
52
|
render: (loaded, props) => {
|
|
65
|
-
//
|
|
53
|
+
// `loaded` will be a map from key path (as returned from the flattened
|
|
54
|
+
// chunk names) to the modules loaded from the loaders. We now have to
|
|
55
|
+
// restore the chunk names' previous shape from this flat record.
|
|
56
|
+
// We do so by taking advantage of the existing `chunkNames` and replacing
|
|
57
|
+
// each chunk name with its loaded module, so we don't create another
|
|
58
|
+
// object from scratch.
|
|
66
59
|
const loadedModules = JSON.parse(JSON.stringify(chunkNames));
|
|
67
|
-
Object.
|
|
68
|
-
|
|
69
|
-
|
|
60
|
+
Object.entries(loaded).forEach(([keyPath, loadedModule]) => {
|
|
61
|
+
// JSON modules are also loaded as `{ default: ... }` (`import()`
|
|
62
|
+
// semantics) but we just want to pass the actual value to props.
|
|
63
|
+
const chunk = loadedModule.default;
|
|
64
|
+
// One loaded chunk can only be one of two things: a module (props) or a
|
|
65
|
+
// component. Modules are always JSON, so `default` always exists. This
|
|
66
|
+
// could only happen with a user-defined component.
|
|
67
|
+
if (!chunk) {
|
|
70
68
|
throw new Error(`The page component at ${path} doesn't have a default export. This makes it impossible to render anything. Consider default-exporting a React component.`);
|
|
71
69
|
}
|
|
72
|
-
|
|
73
|
-
|
|
70
|
+
// A module can be a primitive, for example, if the user stored a string
|
|
71
|
+
// as a prop. However, there seems to be a bug with swc-loader's CJS
|
|
72
|
+
// logic, in that it would load a JSON module with content "foo" as
|
|
73
|
+
// `{ default: "foo", 0: "f", 1: "o", 2: "o" }`. Just to be safe, we
|
|
74
|
+
// first make sure that the chunk is non-primitive.
|
|
75
|
+
if (typeof chunk === 'object' || typeof chunk === 'function') {
|
|
76
|
+
Object.keys(loadedModule)
|
|
74
77
|
.filter((k) => k !== 'default')
|
|
75
78
|
.forEach((nonDefaultKey) => {
|
|
76
|
-
|
|
79
|
+
chunk[nonDefaultKey] = loadedModule[nonDefaultKey];
|
|
77
80
|
});
|
|
78
81
|
}
|
|
82
|
+
// We now have this chunk prepared. Go down the key path and replace the
|
|
83
|
+
// chunk name with the actual chunk.
|
|
79
84
|
let val = loadedModules;
|
|
80
|
-
const
|
|
81
|
-
|
|
85
|
+
const keyPaths = keyPath.split('.');
|
|
86
|
+
keyPaths.slice(0, -1).forEach((k) => {
|
|
82
87
|
val = val[k];
|
|
83
88
|
});
|
|
84
|
-
val[
|
|
89
|
+
val[keyPaths[keyPaths.length - 1]] = chunk;
|
|
85
90
|
});
|
|
86
|
-
const Component = loadedModules.component;
|
|
87
|
-
delete loadedModules.component;
|
|
88
91
|
/* eslint-disable no-underscore-dangle */
|
|
89
|
-
const
|
|
90
|
-
delete loadedModules.
|
|
92
|
+
const Component = loadedModules.__comp;
|
|
93
|
+
delete loadedModules.__comp;
|
|
94
|
+
const routeContext = loadedModules.__context;
|
|
95
|
+
delete loadedModules.__context;
|
|
91
96
|
/* eslint-enable no-underscore-dangle */
|
|
92
97
|
// Is there any way to put this RouteContextProvider upper in the tree?
|
|
93
|
-
return (<RouteContextProvider value={
|
|
98
|
+
return (<RouteContextProvider value={routeContext}>
|
|
94
99
|
<Component {...loadedModules} {...props}/>
|
|
95
100
|
</RouteContextProvider>);
|
|
96
101
|
},
|
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
/// <reference types="@docusaurus/module-type-aliases" />
|
|
8
8
|
import React, { type ReactNode } from 'react';
|
|
9
9
|
import type { Props } from '@docusaurus/ErrorBoundary';
|
|
10
|
-
|
|
10
|
+
declare type State = {
|
|
11
11
|
error: Error | null;
|
|
12
|
-
}
|
|
12
|
+
};
|
|
13
13
|
export default class ErrorBoundary extends React.Component<Props, State> {
|
|
14
14
|
constructor(props: Props);
|
|
15
15
|
componentDidCatch(error: Error): void;
|
|
@@ -5,52 +5,29 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
import React, { isValidElement } from 'react';
|
|
8
|
-
/*
|
|
9
|
-
Minimal implementation of a React interpolate component.
|
|
10
|
-
We don't ship a markdown parser nor a feature-complete i18n library on purpose.
|
|
11
|
-
More details here: https://github.com/facebook/docusaurus/pull/4295
|
|
12
|
-
*/
|
|
13
|
-
const ValueRegexp = /\{\w+\}/g;
|
|
14
|
-
const ValueFoundMarker = '{}'; // does not care much
|
|
15
8
|
export function interpolate(text, values) {
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
//
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
String(value);
|
|
26
|
-
elements.push(element);
|
|
27
|
-
return ValueFoundMarker;
|
|
9
|
+
// eslint-disable-next-line prefer-named-capture-group
|
|
10
|
+
const segments = text.split(/(\{\w+\})/).map((seg, index) => {
|
|
11
|
+
// Odd indices (1, 3, 5...) of the segments are (potentially) interpolatable
|
|
12
|
+
if (index % 2 === 1) {
|
|
13
|
+
const value = values?.[seg.slice(1, -1)];
|
|
14
|
+
if (value !== undefined) {
|
|
15
|
+
return value;
|
|
16
|
+
}
|
|
17
|
+
// No match: add warning? There's no way to "escape" interpolation though
|
|
28
18
|
}
|
|
29
|
-
return
|
|
19
|
+
return seg;
|
|
30
20
|
});
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
21
|
+
if (segments.some((seg) => isValidElement(seg))) {
|
|
22
|
+
return segments
|
|
23
|
+
.map((seg, index) => isValidElement(seg) ? React.cloneElement(seg, { key: index }) : seg)
|
|
24
|
+
.filter((seg) => seg !== '');
|
|
34
25
|
}
|
|
35
|
-
|
|
36
|
-
if (elements.every((el) => typeof el === 'string')) {
|
|
37
|
-
return processedText
|
|
38
|
-
.split(ValueFoundMarker)
|
|
39
|
-
.reduce((str, value, index) => str.concat(value).concat(elements[index] ?? ''), '');
|
|
40
|
-
}
|
|
41
|
-
// JSX interpolation: returns ReactNode
|
|
42
|
-
return processedText.split(ValueFoundMarker).reduce((array, value, index) => [
|
|
43
|
-
...array,
|
|
44
|
-
<React.Fragment key={index}>
|
|
45
|
-
{value}
|
|
46
|
-
{elements[index]}
|
|
47
|
-
</React.Fragment>,
|
|
48
|
-
], []);
|
|
26
|
+
return segments.join('');
|
|
49
27
|
}
|
|
50
28
|
export default function Interpolate({ children, values, }) {
|
|
51
29
|
if (typeof children !== 'string') {
|
|
52
|
-
|
|
53
|
-
throw new Error('The Docusaurus <Interpolate> component only accept simple string values');
|
|
30
|
+
throw new Error(`The Docusaurus <Interpolate> component only accept simple string values. Received: ${isValidElement(children) ? 'React element' : typeof children}`);
|
|
54
31
|
}
|
|
55
32
|
return <>{interpolate(children, values)}</>;
|
|
56
33
|
}
|
|
@@ -4,20 +4,8 @@
|
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
|
+
/// <reference types="@docusaurus/module-type-aliases" />
|
|
7
8
|
import React from 'react';
|
|
8
|
-
import type
|
|
9
|
-
declare
|
|
10
|
-
interface Window {
|
|
11
|
-
docusaurus: typeof docusaurus;
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
declare const _default: React.ForwardRefExoticComponent<Pick<Partial<import("react-router-dom").NavLinkProps<unknown>> & React.ClassAttributes<HTMLAnchorElement> & React.AnchorHTMLAttributes<HTMLAnchorElement> & {
|
|
15
|
-
readonly className?: string | undefined;
|
|
16
|
-
readonly style?: React.CSSProperties | undefined;
|
|
17
|
-
readonly isNavLink?: boolean | undefined;
|
|
18
|
-
readonly to?: string | undefined;
|
|
19
|
-
readonly href?: string | undefined;
|
|
20
|
-
readonly autoAddBaseUrl?: boolean | undefined;
|
|
21
|
-
readonly 'data-noBrokenLinkCheck'?: boolean | undefined;
|
|
22
|
-
}, "children" | "replace" | "slot" | "style" | "title" | "location" | "component" | "exact" | "sensitive" | "strict" | "id" | "lang" | "dir" | "rel" | "href" | "key" | "type" | "isNavLink" | "className" | "to" | "innerRef" | "download" | "hrefLang" | "media" | "ping" | "target" | "referrerPolicy" | "defaultChecked" | "defaultValue" | "suppressContentEditableWarning" | "suppressHydrationWarning" | "accessKey" | "contentEditable" | "contextMenu" | "draggable" | "hidden" | "placeholder" | "spellCheck" | "tabIndex" | "translate" | "radioGroup" | "role" | "about" | "datatype" | "inlist" | "prefix" | "property" | "resource" | "typeof" | "vocab" | "autoCapitalize" | "autoCorrect" | "autoSave" | "color" | "itemProp" | "itemScope" | "itemType" | "itemID" | "itemRef" | "results" | "security" | "unselectable" | "inputMode" | "is" | "aria-activedescendant" | "aria-atomic" | "aria-autocomplete" | "aria-busy" | "aria-checked" | "aria-colcount" | "aria-colindex" | "aria-colspan" | "aria-controls" | "aria-current" | "aria-describedby" | "aria-details" | "aria-disabled" | "aria-dropeffect" | "aria-errormessage" | "aria-expanded" | "aria-flowto" | "aria-grabbed" | "aria-haspopup" | "aria-hidden" | "aria-invalid" | "aria-keyshortcuts" | "aria-label" | "aria-labelledby" | "aria-level" | "aria-live" | "aria-modal" | "aria-multiline" | "aria-multiselectable" | "aria-orientation" | "aria-owns" | "aria-placeholder" | "aria-posinset" | "aria-pressed" | "aria-readonly" | "aria-relevant" | "aria-required" | "aria-roledescription" | "aria-rowcount" | "aria-rowindex" | "aria-rowspan" | "aria-selected" | "aria-setsize" | "aria-sort" | "aria-valuemax" | "aria-valuemin" | "aria-valuenow" | "aria-valuetext" | "dangerouslySetInnerHTML" | "onCopy" | "onCopyCapture" | "onCut" | "onCutCapture" | "onPaste" | "onPasteCapture" | "onCompositionEnd" | "onCompositionEndCapture" | "onCompositionStart" | "onCompositionStartCapture" | "onCompositionUpdate" | "onCompositionUpdateCapture" | "onFocus" | "onFocusCapture" | "onBlur" | "onBlurCapture" | "onChange" | "onChangeCapture" | "onBeforeInput" | "onBeforeInputCapture" | "onInput" | "onInputCapture" | "onReset" | "onResetCapture" | "onSubmit" | "onSubmitCapture" | "onInvalid" | "onInvalidCapture" | "onLoad" | "onLoadCapture" | "onError" | "onErrorCapture" | "onKeyDown" | "onKeyDownCapture" | "onKeyPress" | "onKeyPressCapture" | "onKeyUp" | "onKeyUpCapture" | "onAbort" | "onAbortCapture" | "onCanPlay" | "onCanPlayCapture" | "onCanPlayThrough" | "onCanPlayThroughCapture" | "onDurationChange" | "onDurationChangeCapture" | "onEmptied" | "onEmptiedCapture" | "onEncrypted" | "onEncryptedCapture" | "onEnded" | "onEndedCapture" | "onLoadedData" | "onLoadedDataCapture" | "onLoadedMetadata" | "onLoadedMetadataCapture" | "onLoadStart" | "onLoadStartCapture" | "onPause" | "onPauseCapture" | "onPlay" | "onPlayCapture" | "onPlaying" | "onPlayingCapture" | "onProgress" | "onProgressCapture" | "onRateChange" | "onRateChangeCapture" | "onSeeked" | "onSeekedCapture" | "onSeeking" | "onSeekingCapture" | "onStalled" | "onStalledCapture" | "onSuspend" | "onSuspendCapture" | "onTimeUpdate" | "onTimeUpdateCapture" | "onVolumeChange" | "onVolumeChangeCapture" | "onWaiting" | "onWaitingCapture" | "onAuxClick" | "onAuxClickCapture" | "onClick" | "onClickCapture" | "onContextMenu" | "onContextMenuCapture" | "onDoubleClick" | "onDoubleClickCapture" | "onDrag" | "onDragCapture" | "onDragEnd" | "onDragEndCapture" | "onDragEnter" | "onDragEnterCapture" | "onDragExit" | "onDragExitCapture" | "onDragLeave" | "onDragLeaveCapture" | "onDragOver" | "onDragOverCapture" | "onDragStart" | "onDragStartCapture" | "onDrop" | "onDropCapture" | "onMouseDown" | "onMouseDownCapture" | "onMouseEnter" | "onMouseLeave" | "onMouseMove" | "onMouseMoveCapture" | "onMouseOut" | "onMouseOutCapture" | "onMouseOver" | "onMouseOverCapture" | "onMouseUp" | "onMouseUpCapture" | "onSelect" | "onSelectCapture" | "onTouchCancel" | "onTouchCancelCapture" | "onTouchEnd" | "onTouchEndCapture" | "onTouchMove" | "onTouchMoveCapture" | "onTouchStart" | "onTouchStartCapture" | "onPointerDown" | "onPointerDownCapture" | "onPointerMove" | "onPointerMoveCapture" | "onPointerUp" | "onPointerUpCapture" | "onPointerCancel" | "onPointerCancelCapture" | "onPointerEnter" | "onPointerEnterCapture" | "onPointerLeave" | "onPointerLeaveCapture" | "onPointerOver" | "onPointerOverCapture" | "onPointerOut" | "onPointerOutCapture" | "onGotPointerCapture" | "onGotPointerCaptureCapture" | "onLostPointerCapture" | "onLostPointerCaptureCapture" | "onScroll" | "onScrollCapture" | "onWheel" | "onWheelCapture" | "onAnimationStart" | "onAnimationStartCapture" | "onAnimationEnd" | "onAnimationEndCapture" | "onAnimationIteration" | "onAnimationIterationCapture" | "onTransitionEnd" | "onTransitionEndCapture" | "activeClassName" | "activeStyle" | "isActive" | "data-noBrokenLinkCheck" | "autoAddBaseUrl"> & React.RefAttributes<HTMLAnchorElement>>;
|
|
9
|
+
import type { Props } from '@docusaurus/Link';
|
|
10
|
+
declare const _default: React.ForwardRefExoticComponent<Pick<Props, "children" | "replace" | "slot" | "style" | "title" | "location" | "component" | "exact" | "sensitive" | "strict" | "type" | "key" | "id" | "lang" | "dir" | "rel" | "href" | "isNavLink" | "className" | "to" | "innerRef" | "download" | "hrefLang" | "media" | "ping" | "target" | "referrerPolicy" | "defaultChecked" | "defaultValue" | "suppressContentEditableWarning" | "suppressHydrationWarning" | "accessKey" | "contentEditable" | "contextMenu" | "draggable" | "hidden" | "placeholder" | "spellCheck" | "tabIndex" | "translate" | "radioGroup" | "role" | "about" | "datatype" | "inlist" | "prefix" | "property" | "resource" | "typeof" | "vocab" | "autoCapitalize" | "autoCorrect" | "autoSave" | "color" | "itemProp" | "itemScope" | "itemType" | "itemID" | "itemRef" | "results" | "security" | "unselectable" | "inputMode" | "is" | "aria-activedescendant" | "aria-atomic" | "aria-autocomplete" | "aria-busy" | "aria-checked" | "aria-colcount" | "aria-colindex" | "aria-colspan" | "aria-controls" | "aria-current" | "aria-describedby" | "aria-details" | "aria-disabled" | "aria-dropeffect" | "aria-errormessage" | "aria-expanded" | "aria-flowto" | "aria-grabbed" | "aria-haspopup" | "aria-hidden" | "aria-invalid" | "aria-keyshortcuts" | "aria-label" | "aria-labelledby" | "aria-level" | "aria-live" | "aria-modal" | "aria-multiline" | "aria-multiselectable" | "aria-orientation" | "aria-owns" | "aria-placeholder" | "aria-posinset" | "aria-pressed" | "aria-readonly" | "aria-relevant" | "aria-required" | "aria-roledescription" | "aria-rowcount" | "aria-rowindex" | "aria-rowspan" | "aria-selected" | "aria-setsize" | "aria-sort" | "aria-valuemax" | "aria-valuemin" | "aria-valuenow" | "aria-valuetext" | "dangerouslySetInnerHTML" | "onCopy" | "onCopyCapture" | "onCut" | "onCutCapture" | "onPaste" | "onPasteCapture" | "onCompositionEnd" | "onCompositionEndCapture" | "onCompositionStart" | "onCompositionStartCapture" | "onCompositionUpdate" | "onCompositionUpdateCapture" | "onFocus" | "onFocusCapture" | "onBlur" | "onBlurCapture" | "onChange" | "onChangeCapture" | "onBeforeInput" | "onBeforeInputCapture" | "onInput" | "onInputCapture" | "onReset" | "onResetCapture" | "onSubmit" | "onSubmitCapture" | "onInvalid" | "onInvalidCapture" | "onLoad" | "onLoadCapture" | "onError" | "onErrorCapture" | "onKeyDown" | "onKeyDownCapture" | "onKeyPress" | "onKeyPressCapture" | "onKeyUp" | "onKeyUpCapture" | "onAbort" | "onAbortCapture" | "onCanPlay" | "onCanPlayCapture" | "onCanPlayThrough" | "onCanPlayThroughCapture" | "onDurationChange" | "onDurationChangeCapture" | "onEmptied" | "onEmptiedCapture" | "onEncrypted" | "onEncryptedCapture" | "onEnded" | "onEndedCapture" | "onLoadedData" | "onLoadedDataCapture" | "onLoadedMetadata" | "onLoadedMetadataCapture" | "onLoadStart" | "onLoadStartCapture" | "onPause" | "onPauseCapture" | "onPlay" | "onPlayCapture" | "onPlaying" | "onPlayingCapture" | "onProgress" | "onProgressCapture" | "onRateChange" | "onRateChangeCapture" | "onSeeked" | "onSeekedCapture" | "onSeeking" | "onSeekingCapture" | "onStalled" | "onStalledCapture" | "onSuspend" | "onSuspendCapture" | "onTimeUpdate" | "onTimeUpdateCapture" | "onVolumeChange" | "onVolumeChangeCapture" | "onWaiting" | "onWaitingCapture" | "onAuxClick" | "onAuxClickCapture" | "onClick" | "onClickCapture" | "onContextMenu" | "onContextMenuCapture" | "onDoubleClick" | "onDoubleClickCapture" | "onDrag" | "onDragCapture" | "onDragEnd" | "onDragEndCapture" | "onDragEnter" | "onDragEnterCapture" | "onDragExit" | "onDragExitCapture" | "onDragLeave" | "onDragLeaveCapture" | "onDragOver" | "onDragOverCapture" | "onDragStart" | "onDragStartCapture" | "onDrop" | "onDropCapture" | "onMouseDown" | "onMouseDownCapture" | "onMouseEnter" | "onMouseLeave" | "onMouseMove" | "onMouseMoveCapture" | "onMouseOut" | "onMouseOutCapture" | "onMouseOver" | "onMouseOverCapture" | "onMouseUp" | "onMouseUpCapture" | "onSelect" | "onSelectCapture" | "onTouchCancel" | "onTouchCancelCapture" | "onTouchEnd" | "onTouchEndCapture" | "onTouchMove" | "onTouchMoveCapture" | "onTouchStart" | "onTouchStartCapture" | "onPointerDown" | "onPointerDownCapture" | "onPointerMove" | "onPointerMoveCapture" | "onPointerUp" | "onPointerUpCapture" | "onPointerCancel" | "onPointerCancelCapture" | "onPointerEnter" | "onPointerEnterCapture" | "onPointerLeave" | "onPointerLeaveCapture" | "onPointerOver" | "onPointerOverCapture" | "onPointerOut" | "onPointerOutCapture" | "onGotPointerCapture" | "onGotPointerCaptureCapture" | "onLostPointerCapture" | "onLostPointerCaptureCapture" | "onScroll" | "onScrollCapture" | "onWheel" | "onWheelCapture" | "onAnimationStart" | "onAnimationStartCapture" | "onAnimationEnd" | "onAnimationEndCapture" | "onAnimationIteration" | "onAnimationIterationCapture" | "onTransitionEnd" | "onTransitionEndCapture" | "activeClassName" | "activeStyle" | "isActive" | "data-noBrokenLinkCheck" | "autoAddBaseUrl"> & React.RefAttributes<HTMLAnchorElement>>;
|
|
23
11
|
export default _default;
|
|
@@ -54,32 +54,27 @@ function Link({ isNavLink, to, href, activeClassName, isActive, 'data-noBrokenLi
|
|
|
54
54
|
const LinkComponent = (isNavLink ? NavLink : RRLink);
|
|
55
55
|
const IOSupported = ExecutionEnvironment.canUseIntersectionObserver;
|
|
56
56
|
const ioRef = useRef();
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if (el === entry.target) {
|
|
61
|
-
// If element is in viewport, stop observing and run callback.
|
|
62
|
-
// https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
|
|
63
|
-
if (entry.isIntersecting || entry.intersectionRatio > 0) {
|
|
64
|
-
ioRef.current.unobserve(el);
|
|
65
|
-
ioRef.current.disconnect();
|
|
66
|
-
cb();
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
});
|
|
71
|
-
// Add element to the observer.
|
|
72
|
-
ioRef.current.observe(el);
|
|
73
|
-
};
|
|
74
|
-
const handleRef = (ref) => {
|
|
75
|
-
innerRef.current = ref;
|
|
76
|
-
if (IOSupported && ref && isInternal) {
|
|
57
|
+
const handleRef = (el) => {
|
|
58
|
+
innerRef.current = el;
|
|
59
|
+
if (IOSupported && el && isInternal) {
|
|
77
60
|
// If IO supported and element reference found, set up Observer.
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
61
|
+
ioRef.current = new window.IntersectionObserver((entries) => {
|
|
62
|
+
entries.forEach((entry) => {
|
|
63
|
+
if (el === entry.target) {
|
|
64
|
+
// If element is in viewport, stop observing and run callback.
|
|
65
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
|
|
66
|
+
if (entry.isIntersecting || entry.intersectionRatio > 0) {
|
|
67
|
+
ioRef.current.unobserve(el);
|
|
68
|
+
ioRef.current.disconnect();
|
|
69
|
+
if (targetLink != null) {
|
|
70
|
+
window.docusaurus.prefetch(targetLink);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
});
|
|
82
75
|
});
|
|
76
|
+
// Add element to the observer.
|
|
77
|
+
ioRef.current.observe(el);
|
|
83
78
|
}
|
|
84
79
|
};
|
|
85
80
|
const onMouseEnter = () => {
|
|
@@ -104,14 +99,14 @@ function Link({ isNavLink, to, href, activeClassName, isActive, 'data-noBrokenLi
|
|
|
104
99
|
}, [ioRef, targetLink, IOSupported, isInternal]);
|
|
105
100
|
const isAnchorLink = targetLink?.startsWith('#') ?? false;
|
|
106
101
|
const isRegularHtmlLink = !targetLink || !isInternal || isAnchorLink;
|
|
107
|
-
if (
|
|
102
|
+
if (!isRegularHtmlLink && !noBrokenLinkCheck) {
|
|
108
103
|
linksCollector.collectLink(targetLink);
|
|
109
104
|
}
|
|
110
105
|
return isRegularHtmlLink ? (
|
|
111
106
|
// eslint-disable-next-line jsx-a11y/anchor-has-content
|
|
112
107
|
<a ref={innerRef} href={targetLink} {...(targetLinkUnprefixed &&
|
|
113
108
|
!isInternal && { target: '_blank', rel: 'noopener noreferrer' })} {...props}/>) : (<LinkComponent {...props} onMouseEnter={onMouseEnter} innerRef={handleRef} to={targetLink}
|
|
114
|
-
//
|
|
109
|
+
// Avoid "React does not recognize the `activeClassName` prop on a DOM
|
|
115
110
|
// element"
|
|
116
111
|
{...(isNavLink && { isActive, activeClassName })}/>);
|
|
117
112
|
}
|
|
@@ -7,15 +7,9 @@
|
|
|
7
7
|
import useDocusaurusContext from './useDocusaurusContext';
|
|
8
8
|
import { hasProtocol } from './isInternalUrl';
|
|
9
9
|
function addBaseUrl(siteUrl, baseUrl, url, { forcePrependBaseUrl = false, absolute = false } = {}) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
// it never makes sense to add a base url to a local anchor url
|
|
14
|
-
if (url.startsWith('#')) {
|
|
15
|
-
return url;
|
|
16
|
-
}
|
|
17
|
-
// it never makes sense to add a base url to an url with a protocol
|
|
18
|
-
if (hasProtocol(url)) {
|
|
10
|
+
// It never makes sense to add base url to a local anchor url, or one with a
|
|
11
|
+
// protocol
|
|
12
|
+
if (!url || url.startsWith('#') || hasProtocol(url)) {
|
|
19
13
|
return url;
|
|
20
14
|
}
|
|
21
15
|
if (forcePrependBaseUrl) {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
|
-
import type { GlobalData } from '@docusaurus/types';
|
|
7
|
+
import type { GlobalData, UseDataOptions } from '@docusaurus/types';
|
|
8
8
|
export default function useGlobalData(): GlobalData;
|
|
9
|
-
export declare function useAllPluginInstancesData(pluginName: string): GlobalData[string];
|
|
10
|
-
export declare function usePluginData(pluginName: string, pluginId?: string): GlobalData[string][string];
|
|
9
|
+
export declare function useAllPluginInstancesData(pluginName: string, options?: UseDataOptions): GlobalData[string] | undefined;
|
|
10
|
+
export declare function usePluginData(pluginName: string, pluginId?: string, options?: UseDataOptions): GlobalData[string][string];
|
|
@@ -13,18 +13,18 @@ export default function useGlobalData() {
|
|
|
13
13
|
}
|
|
14
14
|
return globalData;
|
|
15
15
|
}
|
|
16
|
-
export function useAllPluginInstancesData(pluginName) {
|
|
16
|
+
export function useAllPluginInstancesData(pluginName, options = {}) {
|
|
17
17
|
const globalData = useGlobalData();
|
|
18
18
|
const pluginGlobalData = globalData[pluginName];
|
|
19
|
-
if (!pluginGlobalData) {
|
|
19
|
+
if (!pluginGlobalData && options.failfast) {
|
|
20
20
|
throw new Error(`Docusaurus plugin global data not found for "${pluginName}" plugin.`);
|
|
21
21
|
}
|
|
22
22
|
return pluginGlobalData;
|
|
23
23
|
}
|
|
24
|
-
export function usePluginData(pluginName, pluginId = DEFAULT_PLUGIN_ID) {
|
|
24
|
+
export function usePluginData(pluginName, pluginId = DEFAULT_PLUGIN_ID, options = {}) {
|
|
25
25
|
const pluginGlobalData = useAllPluginInstancesData(pluginName);
|
|
26
|
-
const pluginInstanceGlobalData = pluginGlobalData[pluginId];
|
|
27
|
-
if (!pluginInstanceGlobalData) {
|
|
26
|
+
const pluginInstanceGlobalData = pluginGlobalData?.[pluginId];
|
|
27
|
+
if (!pluginInstanceGlobalData && options.failfast) {
|
|
28
28
|
throw new Error(`Docusaurus plugin global data not found for "${pluginName}" plugin with id "${pluginId}".`);
|
|
29
29
|
}
|
|
30
30
|
return pluginInstanceGlobalData;
|
package/lib/client/flat.d.ts
CHANGED
|
@@ -4,7 +4,15 @@
|
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
|
-
import type {
|
|
8
|
-
|
|
7
|
+
import type { ChunkNames } from '@docusaurus/types';
|
|
8
|
+
/**
|
|
9
|
+
* Takes a tree, and flattens it into a map of keyPath -> value.
|
|
10
|
+
*
|
|
11
|
+
* ```js
|
|
12
|
+
* flat({ a: { b: 1 } }) === { "a.b": 1 };
|
|
13
|
+
* flat({ a: [1, 2] }) === { "a.0": 1, "a.1": 2 };
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export default function flat(target: ChunkNames): {
|
|
9
17
|
[keyPath: string]: string;
|
|
10
18
|
};
|
package/lib/client/flat.js
CHANGED
|
@@ -5,20 +5,28 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
const isTree = (x) => typeof x === 'object' && !!x && Object.keys(x).length > 0;
|
|
8
|
+
/**
|
|
9
|
+
* Takes a tree, and flattens it into a map of keyPath -> value.
|
|
10
|
+
*
|
|
11
|
+
* ```js
|
|
12
|
+
* flat({ a: { b: 1 } }) === { "a.b": 1 };
|
|
13
|
+
* flat({ a: [1, 2] }) === { "a.0": 1, "a.1": 2 };
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
8
16
|
export default function flat(target) {
|
|
9
17
|
const delimiter = '.';
|
|
10
18
|
const output = {};
|
|
11
|
-
function
|
|
19
|
+
function dfs(object, prefix) {
|
|
12
20
|
Object.entries(object).forEach(([key, value]) => {
|
|
13
21
|
const newKey = prefix ? `${prefix}${delimiter}${key}` : key;
|
|
14
22
|
if (isTree(value)) {
|
|
15
|
-
|
|
23
|
+
dfs(value, newKey);
|
|
16
24
|
}
|
|
17
25
|
else {
|
|
18
26
|
output[newKey] = value;
|
|
19
27
|
}
|
|
20
28
|
});
|
|
21
29
|
}
|
|
22
|
-
|
|
30
|
+
dfs(target);
|
|
23
31
|
return output;
|
|
24
32
|
}
|
|
@@ -4,17 +4,26 @@
|
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
|
+
import { matchRoutes } from 'react-router-config';
|
|
8
|
+
import routes from '@generated/routes';
|
|
7
9
|
// Memoize previously normalized pathnames.
|
|
8
|
-
const pathnames =
|
|
10
|
+
const pathnames = new Map();
|
|
9
11
|
export default function normalizeLocation(location) {
|
|
10
|
-
if (pathnames
|
|
12
|
+
if (pathnames.has(location.pathname)) {
|
|
11
13
|
return {
|
|
12
14
|
...location,
|
|
13
|
-
pathname: pathnames
|
|
15
|
+
pathname: pathnames.get(location.pathname),
|
|
14
16
|
};
|
|
15
17
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
+
// If the location was registered with an `.html` extension, we don't strip it
|
|
19
|
+
// away, or it will render to a 404 page.
|
|
20
|
+
const matchedRoutes = matchRoutes(routes, location.pathname);
|
|
21
|
+
if (matchedRoutes.some(({ route }) => route.exact === true)) {
|
|
22
|
+
pathnames.set(location.pathname, location.pathname);
|
|
23
|
+
return location;
|
|
24
|
+
}
|
|
25
|
+
const pathname = location.pathname.trim().replace(/(?:\/index)?\.html$/, '') || '/';
|
|
26
|
+
pathnames.set(location.pathname, pathname);
|
|
18
27
|
return {
|
|
19
28
|
...location,
|
|
20
29
|
pathname,
|