@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.
Files changed (130) hide show
  1. package/bin/beforeCli.mjs +12 -7
  2. package/bin/docusaurus.mjs +21 -72
  3. package/lib/client/.eslintrc.js +2 -3
  4. package/lib/client/App.d.ts +1 -1
  5. package/lib/client/App.js +9 -5
  6. package/lib/client/{baseUrlIssueBanner/BaseUrlIssueBanner.d.ts → BaseUrlIssueBanner/index.d.ts} +10 -5
  7. package/lib/client/{baseUrlIssueBanner/BaseUrlIssueBanner.js → BaseUrlIssueBanner/index.js} +14 -9
  8. package/lib/client/{baseUrlIssueBanner → BaseUrlIssueBanner}/styles.module.css +0 -0
  9. package/lib/client/ClientLifecyclesDispatcher.d.ts +16 -0
  10. package/lib/client/ClientLifecyclesDispatcher.js +34 -0
  11. package/lib/client/LinksCollector.js +1 -2
  12. package/lib/client/PendingNavigation.d.ts +8 -17
  13. package/lib/client/PendingNavigation.js +39 -70
  14. package/lib/client/clientEntry.js +1 -2
  15. package/lib/client/docusaurus.d.ts +5 -5
  16. package/lib/client/docusaurus.js +25 -29
  17. package/lib/client/exports/BrowserOnly.d.ts +3 -4
  18. package/lib/client/exports/BrowserOnly.js +1 -1
  19. package/lib/client/exports/ComponentCreator.js +51 -46
  20. package/lib/client/exports/ErrorBoundary.d.ts +2 -2
  21. package/lib/client/exports/Interpolate.js +16 -39
  22. package/lib/client/exports/Link.d.ts +3 -15
  23. package/lib/client/exports/Link.js +21 -26
  24. package/lib/client/exports/useBaseUrl.js +3 -9
  25. package/lib/client/exports/useGlobalData.d.ts +3 -3
  26. package/lib/client/exports/useGlobalData.js +5 -5
  27. package/lib/client/flat.d.ts +10 -2
  28. package/lib/client/flat.js +11 -3
  29. package/lib/client/normalizeLocation.js +14 -5
  30. package/lib/client/prefetch.js +7 -25
  31. package/lib/client/preload.d.ts +1 -3
  32. package/lib/client/preload.js +2 -2
  33. package/lib/client/routeContext.js +1 -1
  34. package/lib/client/serverEntry.js +12 -11
  35. package/lib/client/theme-fallback/Error/index.js +2 -0
  36. package/lib/client/theme-fallback/Loading/index.js +2 -0
  37. package/lib/client/theme-fallback/NotFound/index.js +2 -0
  38. package/lib/commands/build.d.ts +6 -2
  39. package/lib/commands/build.js +35 -15
  40. package/lib/commands/clear.d.ts +1 -1
  41. package/lib/commands/clear.js +3 -2
  42. package/lib/commands/deploy.d.ts +5 -2
  43. package/lib/commands/deploy.js +12 -9
  44. package/lib/commands/external.d.ts +1 -1
  45. package/lib/commands/external.js +5 -6
  46. package/lib/commands/serve.d.ts +7 -2
  47. package/lib/commands/serve.js +12 -12
  48. package/lib/commands/start.d.ts +8 -2
  49. package/lib/commands/start.js +14 -9
  50. package/lib/commands/swizzle/actions.d.ts +2 -2
  51. package/lib/commands/swizzle/actions.js +5 -4
  52. package/lib/commands/swizzle/common.d.ts +3 -3
  53. package/lib/commands/swizzle/components.js +41 -3
  54. package/lib/commands/swizzle/config.js +14 -11
  55. package/lib/commands/swizzle/context.js +6 -10
  56. package/lib/commands/swizzle/index.d.ts +2 -2
  57. package/lib/commands/swizzle/index.js +4 -3
  58. package/lib/commands/writeHeadingIds.d.ts +1 -1
  59. package/lib/commands/writeHeadingIds.js +5 -8
  60. package/lib/commands/writeTranslations.d.ts +3 -4
  61. package/lib/commands/writeTranslations.js +7 -9
  62. package/lib/index.d.ts +9 -10
  63. package/lib/index.js +18 -19
  64. package/lib/server/brokenLinks.js +1 -2
  65. package/lib/server/{client-modules/index.d.ts → clientModules.d.ts} +5 -1
  66. package/lib/server/{client-modules/index.js → clientModules.js} +6 -1
  67. package/lib/server/config.d.ts +5 -2
  68. package/lib/server/config.js +11 -6
  69. package/lib/server/configValidation.js +6 -5
  70. package/lib/server/getHostPort.d.ts +14 -0
  71. package/lib/{choosePort.js → server/getHostPort.js} +21 -35
  72. package/lib/server/htmlTags.d.ts +12 -0
  73. package/lib/server/htmlTags.js +62 -0
  74. package/lib/server/i18n.d.ts +2 -11
  75. package/lib/server/i18n.js +4 -19
  76. package/lib/server/index.d.ts +28 -13
  77. package/lib/server/index.js +42 -210
  78. package/lib/server/plugins/configs.d.ts +51 -0
  79. package/lib/server/plugins/configs.js +101 -0
  80. package/lib/server/plugins/index.d.ts +8 -7
  81. package/lib/server/plugins/index.js +59 -134
  82. package/lib/server/plugins/init.d.ts +6 -19
  83. package/lib/server/plugins/init.js +16 -68
  84. package/lib/server/{moduleShorthand.d.ts → plugins/moduleShorthand.d.ts} +0 -0
  85. package/lib/server/{moduleShorthand.js → plugins/moduleShorthand.js} +0 -0
  86. package/lib/server/plugins/pluginIds.d.ts +4 -0
  87. package/lib/server/plugins/pluginIds.js +4 -2
  88. package/lib/server/plugins/presets.d.ts +12 -0
  89. package/lib/server/{presets/index.js → plugins/presets.js} +14 -6
  90. package/lib/server/plugins/{applyRouteTrailingSlash.d.ts → routeConfig.d.ts} +3 -1
  91. package/lib/server/plugins/routeConfig.js +54 -0
  92. package/lib/server/plugins/synthetic.d.ts +20 -0
  93. package/lib/server/plugins/synthetic.js +112 -0
  94. package/lib/server/routes.d.ts +42 -8
  95. package/lib/server/routes.js +150 -92
  96. package/lib/server/{versions/index.d.ts → siteMetadata.d.ts} +5 -2
  97. package/lib/server/{versions/index.js → siteMetadata.js} +36 -3
  98. package/lib/server/translations/translations.d.ts +5 -13
  99. package/lib/server/translations/translations.js +5 -8
  100. package/lib/server/translations/translationsExtractor.d.ts +2 -4
  101. package/lib/webpack/aliases/index.d.ts +34 -0
  102. package/lib/webpack/aliases/index.js +106 -0
  103. package/lib/webpack/base.d.ts +0 -3
  104. package/lib/webpack/base.js +8 -25
  105. package/lib/webpack/client.js +1 -1
  106. package/lib/webpack/plugins/CleanWebpackPlugin.d.ts +2 -2
  107. package/lib/webpack/plugins/WaitPlugin.d.ts +2 -2
  108. package/lib/webpack/server.d.ts +2 -2
  109. package/lib/webpack/server.js +5 -3
  110. package/lib/webpack/utils.d.ts +3 -3
  111. package/lib/webpack/utils.js +3 -3
  112. package/package.json +33 -36
  113. package/lib/choosePort.d.ts +0 -11
  114. package/lib/client/client-lifecycles-dispatcher.d.ts +0 -9
  115. package/lib/client/client-lifecycles-dispatcher.js +0 -23
  116. package/lib/client/nprogress.css +0 -36
  117. package/lib/commands/commandUtils.d.ts +0 -9
  118. package/lib/commands/commandUtils.js +0 -21
  119. package/lib/server/duplicateRoutes.d.ts +0 -8
  120. package/lib/server/duplicateRoutes.js +0 -42
  121. package/lib/server/html-tags/htmlTags.d.ts +0 -7
  122. package/lib/server/html-tags/htmlTags.js +0 -38
  123. package/lib/server/html-tags/index.d.ts +0 -8
  124. package/lib/server/html-tags/index.js +0 -42
  125. package/lib/server/plugins/applyRouteTrailingSlash.js +0 -19
  126. package/lib/server/presets/index.d.ts +0 -11
  127. package/lib/server/themes/alias.d.ts +0 -9
  128. package/lib/server/themes/alias.js +0 -50
  129. package/lib/server/themes/index.d.ts +0 -12
  130. package/lib/server/themes/index.js +0 -47
@@ -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[routePath] && !fetched[routePath];
19
- const canPreload = (routePath) => !isSlowConnection() && !loaded[routePath];
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
- const removeRouteNameHash = (str) => str.replace(/-[^-]+$/, '');
24
- const getChunkNamesToLoad = (path) => Object.entries(routesChunkNames)
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: (routePath) => {
28
+ prefetch(routePath) {
31
29
  if (!canPrefetch(routePath)) {
32
30
  return false;
33
31
  }
34
- // Prevent future duplicate prefetch of routePath.
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.forEach((chunkName) => {
41
- // "__webpack_require__.gca" is a custom function provided by
42
- // ChunkAssetPlugin. Pass it the chunkName or chunkId you want to load and
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 & hence the
47
- // chunk assets are merged to another chunk/previous chunk.
48
- // Hence, we can safely filter it out/don't need to load it.
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
- return true;
48
+ return Promise.resolve();
49
+ }));
54
50
  },
55
- preload: (routePath) => {
51
+ preload(routePath) {
56
52
  if (!canPreload(routePath)) {
57
53
  return false;
58
54
  }
59
- loaded[routePath] = true;
60
- preloadHelper(routes, routePath);
61
- return true;
55
+ loaded.add(routePath);
56
+ return preloadHelper(routePath);
62
57
  },
63
58
  };
64
- export default docusaurus;
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
- export default function BrowserOnly({ children, fallback, }: {
9
- children: () => JSX.Element;
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: async () => {
20
- const NotFound = (await import('@theme/NotFound')).default;
21
- return (props) => (
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 chunkNamesKey = `${path}-${hash}`;
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 optsLoader = {};
35
- /* Prepare opts data that react-loadable needs
36
- https://github.com/jamiebuilds/react-loadable#declaring-which-modules-are-being-loaded
37
- Example:
38
- - optsLoader:
39
- {
40
- component: () => import('./Pages.js'),
41
- content.foo: () => import('./doc1.md'),
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(([key, chunkName]) => {
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
- optsLoader[key] = chunkRegistry[0];
55
- optsModules.push(chunkRegistry[1]);
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: optsLoader,
62
- modules: optsModules,
49
+ loader,
50
+ modules,
63
51
  webpack: () => optsWebpack,
64
52
  render: (loaded, props) => {
65
- // Clone the original object since we don't want to alter the original.
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.keys(loaded).forEach((key) => {
68
- const newComp = loaded[key].default;
69
- if (!newComp) {
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
- if (typeof newComp === 'object' || typeof newComp === 'function') {
73
- Object.keys(loaded[key])
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
- newComp[nonDefaultKey] = loaded[key][nonDefaultKey];
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 keyPath = key.split('.');
81
- keyPath.slice(0, -1).forEach((k) => {
85
+ const keyPaths = keyPath.split('.');
86
+ keyPaths.slice(0, -1).forEach((k) => {
82
87
  val = val[k];
83
88
  });
84
- val[keyPath[keyPath.length - 1]] = newComp;
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 routeContextModule = loadedModules.__routeContextModule;
90
- delete loadedModules.__routeContextModule;
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={routeContextModule}>
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
- interface State {
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
- const elements = [];
17
- const processedText = text.replace(ValueRegexp, (match) => {
18
- // remove {{ and }} around the placeholder
19
- const key = match.substring(1, match.length - 1);
20
- const value = values?.[key];
21
- if (typeof value !== 'undefined') {
22
- const element = isValidElement(value)
23
- ? value
24
- : // For non-React elements: basic primitive->string conversion
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 match; // no match? add warning?
19
+ return seg;
30
20
  });
31
- // No interpolation to be done: just return the text
32
- if (elements.length === 0) {
33
- return text;
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
- // Basic string interpolation: returns interpolated string
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
- console.warn('Illegal <Interpolate> children', children);
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 docusaurus from '../docusaurus';
9
- declare global {
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 handleIntersection = (el, cb) => {
58
- ioRef.current = new window.IntersectionObserver((entries) => {
59
- entries.forEach((entry) => {
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
- handleIntersection(ref, () => {
79
- if (targetLink != null) {
80
- window.docusaurus.prefetch(targetLink);
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 (targetLink && isInternal && !isAnchorLink && !noBrokenLinkCheck) {
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
- // avoid "React does not recognize the `activeClassName` prop on a DOM
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
- if (!url) {
11
- return url;
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;
@@ -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 { RouteChunksTree } from '@docusaurus/types';
8
- export default function flat(target: RouteChunksTree): {
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
  };
@@ -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 step(object, prefix) {
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
- step(value, newKey);
23
+ dfs(value, newKey);
16
24
  }
17
25
  else {
18
26
  output[newKey] = value;
19
27
  }
20
28
  });
21
29
  }
22
- step(target);
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[location.pathname]) {
12
+ if (pathnames.has(location.pathname)) {
11
13
  return {
12
14
  ...location,
13
- pathname: pathnames[location.pathname],
15
+ pathname: pathnames.get(location.pathname),
14
16
  };
15
17
  }
16
- const pathname = location.pathname.trim().replace(/\/index\.html$/, '') || '/';
17
- pathnames[location.pathname] = pathname;
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,