@docusaurus/core 2.0.0-beta.17 → 2.0.0-beta.18

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 (94) hide show
  1. package/bin/beforeCli.mjs +2 -5
  2. package/bin/docusaurus.mjs +20 -21
  3. package/lib/choosePort.js +3 -6
  4. package/lib/client/App.js +6 -2
  5. package/lib/client/LinksCollector.d.ts +1 -1
  6. package/lib/client/LinksCollector.js +3 -3
  7. package/lib/client/SiteMetadataDefaults.d.ts +8 -0
  8. package/lib/client/SiteMetadataDefaults.js +19 -0
  9. package/lib/client/{exports/browserContext.d.ts → browserContext.d.ts} +0 -0
  10. package/lib/client/{exports/browserContext.js → browserContext.js} +0 -0
  11. package/lib/client/clientEntry.js +2 -2
  12. package/lib/client/{exports/docusaurusContext.d.ts → docusaurusContext.d.ts} +0 -0
  13. package/lib/client/{exports/docusaurusContext.js → docusaurusContext.js} +0 -0
  14. package/lib/client/exports/BrowserOnly.js +1 -1
  15. package/lib/client/exports/ComponentCreator.js +34 -14
  16. package/lib/client/exports/Interpolate.d.ts +1 -1
  17. package/lib/client/exports/Interpolate.js +4 -4
  18. package/lib/client/exports/Link.d.ts +1 -1
  19. package/lib/client/exports/Link.js +1 -1
  20. package/lib/client/exports/Translate.d.ts +2 -2
  21. package/lib/client/exports/Translate.js +2 -1
  22. package/lib/client/exports/useBaseUrl.js +5 -0
  23. package/lib/client/exports/useDocusaurusContext.js +1 -1
  24. package/lib/client/exports/useGlobalData.d.ts +4 -3
  25. package/lib/client/exports/useIsBrowser.js +1 -1
  26. package/lib/client/exports/useRouteContext.d.ts +8 -0
  27. package/lib/client/exports/useRouteContext.js +15 -0
  28. package/lib/client/flat.d.ts +3 -1
  29. package/lib/client/flat.js +1 -2
  30. package/lib/client/normalizeLocation.js +1 -5
  31. package/lib/client/prefetch.js +3 -3
  32. package/lib/client/preload.js +3 -9
  33. package/lib/client/routeContext.d.ts +13 -0
  34. package/lib/client/routeContext.js +31 -0
  35. package/lib/client/serverEntry.js +7 -7
  36. package/lib/client/theme-fallback/Error/index.js +5 -1
  37. package/lib/client/theme-fallback/Layout/index.d.ts +1 -1
  38. package/lib/client/theme-fallback/Layout/index.js +2 -17
  39. package/lib/client/theme-fallback/NotFound/index.js +11 -5
  40. package/lib/client/theme-fallback/Root/index.d.ts +4 -4
  41. package/lib/client/theme-fallback/Root/index.js +2 -1
  42. package/lib/client/theme-fallback/SiteMetadata/index.d.ts +8 -0
  43. package/lib/client/theme-fallback/SiteMetadata/index.js +10 -0
  44. package/lib/commands/build.js +1 -1
  45. package/lib/commands/commandUtils.js +1 -1
  46. package/lib/commands/deploy.d.ts +0 -3
  47. package/lib/commands/deploy.js +4 -31
  48. package/lib/commands/external.js +1 -5
  49. package/lib/commands/start.js +7 -8
  50. package/lib/commands/swizzle/actions.js +1 -2
  51. package/lib/commands/swizzle/context.js +1 -3
  52. package/lib/commands/swizzle/tables.js +7 -10
  53. package/lib/commands/swizzle/themes.js +5 -2
  54. package/lib/commands/writeHeadingIds.d.ts +2 -9
  55. package/lib/commands/writeHeadingIds.js +2 -57
  56. package/lib/server/brokenLinks.d.ts +3 -16
  57. package/lib/server/brokenLinks.js +12 -19
  58. package/lib/server/client-modules/index.d.ts +2 -2
  59. package/lib/server/client-modules/index.js +4 -1
  60. package/lib/server/config.js +1 -1
  61. package/lib/server/configValidation.d.ts +1 -1
  62. package/lib/server/configValidation.js +34 -9
  63. package/lib/server/duplicateRoutes.d.ts +0 -2
  64. package/lib/server/duplicateRoutes.js +8 -8
  65. package/lib/server/html-tags/htmlTags.js +1 -1
  66. package/lib/server/html-tags/index.d.ts +1 -2
  67. package/lib/server/html-tags/index.js +2 -3
  68. package/lib/server/i18n.d.ts +1 -1
  69. package/lib/server/i18n.js +2 -9
  70. package/lib/server/index.js +36 -31
  71. package/lib/server/plugins/index.d.ts +2 -2
  72. package/lib/server/plugins/index.js +25 -12
  73. package/lib/server/plugins/init.d.ts +6 -2
  74. package/lib/server/plugins/init.js +34 -37
  75. package/lib/server/presets/index.js +7 -13
  76. package/lib/server/routes.d.ts +2 -4
  77. package/lib/server/routes.js +23 -12
  78. package/lib/server/themes/alias.js +3 -1
  79. package/lib/server/themes/index.js +4 -4
  80. package/lib/server/translations/translations.d.ts +12 -13
  81. package/lib/server/translations/translations.js +4 -10
  82. package/lib/server/translations/translationsExtractor.d.ts +3 -1
  83. package/lib/server/translations/translationsExtractor.js +3 -4
  84. package/lib/server/versions/index.d.ts +2 -2
  85. package/lib/server/versions/index.js +2 -5
  86. package/lib/webpack/base.d.ts +3 -1
  87. package/lib/webpack/plugins/ChunkAssetPlugin.js +7 -7
  88. package/lib/webpack/plugins/CleanWebpackPlugin.js +1 -1
  89. package/lib/webpack/utils.d.ts +6 -0
  90. package/lib/webpack/utils.js +1 -3
  91. package/package.json +26 -26
  92. package/lib/server/versions/__fixtures__/dummy-plugin.d.ts +0 -0
  93. package/lib/server/versions/__fixtures__/dummy-plugin.js +0 -0
  94. package/lib/server/versions/__fixtures__/package.json +0 -3
package/bin/beforeCli.mjs CHANGED
@@ -72,8 +72,7 @@ export default async function beforeCli() {
72
72
  * @param {import('update-notifier').UpdateInfo} update
73
73
  */
74
74
  function ignoreUpdate(update) {
75
- const isCanaryRelease =
76
- update && update.current && update.current.startsWith('0.0.0');
75
+ const isCanaryRelease = update?.current?.startsWith('0.0.0');
77
76
  return isCanaryRelease;
78
77
  }
79
78
 
@@ -98,9 +97,7 @@ export default async function beforeCli() {
98
97
  .filter((p) => p.startsWith('@docusaurus'))
99
98
  .map((p) => p.concat('@latest'))
100
99
  .join(' ');
101
- const isYarnUsed = await fs.pathExists(
102
- path.resolve(process.cwd(), 'yarn.lock'),
103
- );
100
+ const isYarnUsed = await fs.pathExists(path.resolve('yarn.lock'));
104
101
  const upgradeCommand = isYarnUsed
105
102
  ? `yarn upgrade ${siteDocusaurusPackagesForUpdate}`
106
103
  : `npm i ${siteDocusaurusPackagesForUpdate}`;
@@ -245,34 +245,33 @@ cli.arguments('<command>').action((cmd) => {
245
245
  });
246
246
 
247
247
  /**
248
- * @param {string} command
248
+ * @param {string | undefined} command
249
249
  */
250
250
  function isInternalCommand(command) {
251
- return [
252
- 'start',
253
- 'build',
254
- 'swizzle',
255
- 'deploy',
256
- 'serve',
257
- 'clear',
258
- 'write-translations',
259
- 'write-heading-ids',
260
- ].includes(command);
251
+ return (
252
+ command &&
253
+ [
254
+ 'start',
255
+ 'build',
256
+ 'swizzle',
257
+ 'deploy',
258
+ 'serve',
259
+ 'clear',
260
+ 'write-translations',
261
+ 'write-heading-ids',
262
+ ].includes(command)
263
+ );
261
264
  }
262
265
 
263
- async function run() {
264
- if (!isInternalCommand(process.argv.slice(2)[0])) {
265
- await externalCommand(cli, await resolveDir('.'));
266
- }
267
-
268
- cli.parse(process.argv);
266
+ if (!isInternalCommand(process.argv.slice(2)[0])) {
267
+ await externalCommand(cli, await resolveDir('.'));
268
+ }
269
269
 
270
- if (!process.argv.slice(2).length) {
271
- cli.outputHelp();
272
- }
270
+ if (!process.argv.slice(2).length) {
271
+ cli.outputHelp();
273
272
  }
274
273
 
275
- run();
274
+ cli.parse(process.argv);
276
275
 
277
276
  process.on('unhandledRejection', (err) => {
278
277
  logger.error(err);
package/lib/choosePort.js CHANGED
@@ -22,7 +22,7 @@ const execOptions = {
22
22
  stdio: [
23
23
  'pipe',
24
24
  'pipe',
25
- 'ignore', // stderr
25
+ 'ignore',
26
26
  ],
27
27
  };
28
28
  // Clears console
@@ -32,20 +32,17 @@ function clearConsole() {
32
32
  // Gets process id of what is on port
33
33
  function getProcessIdOnPort(port) {
34
34
  return (0, child_process_1.execSync)(`lsof -i:${port} -P -t -sTCP:LISTEN`, execOptions)
35
- .toString()
36
35
  .split('\n')[0]
37
36
  .trim();
38
37
  }
39
38
  // Gets process command
40
39
  function getProcessCommand(processId) {
41
40
  const command = (0, child_process_1.execSync)(`ps -o command -p ${processId} | sed -n 2p`, execOptions);
42
- return command.toString().replace(/\n$/, '');
41
+ return command.replace(/\n$/, '');
43
42
  }
44
43
  // Gets directory of a process from its process id
45
44
  function getDirectoryOfProcessById(processId) {
46
- return (0, child_process_1.execSync)(`lsof -p ${processId} | awk '$4=="cwd" {for (i=9; i<=NF; i++) printf "%s ", $i}'`, execOptions)
47
- .toString()
48
- .trim();
45
+ return (0, child_process_1.execSync)(`lsof -p ${processId} | awk '$4=="cwd" {for (i=9; i<=NF; i++) printf "%s ", $i}'`, execOptions).trim();
49
46
  }
50
47
  // Gets process on port
51
48
  function getProcessForPort(port) {
package/lib/client/App.js CHANGED
@@ -7,11 +7,13 @@
7
7
  import React from 'react';
8
8
  import routes from '@generated/routes';
9
9
  import renderRoutes from './exports/renderRoutes';
10
- import { BrowserContextProvider } from './exports/browserContext';
11
- import { DocusaurusContextProvider } from './exports/docusaurusContext';
10
+ import { BrowserContextProvider } from './browserContext';
11
+ import { DocusaurusContextProvider } from './docusaurusContext';
12
12
  import PendingNavigation from './PendingNavigation';
13
13
  import BaseUrlIssueBanner from './baseUrlIssueBanner/BaseUrlIssueBanner';
14
+ import SiteMetadataDefaults from './SiteMetadataDefaults';
14
15
  import Root from '@theme/Root';
16
+ import SiteMetadata from '@theme/SiteMetadata';
15
17
  import './client-lifecycles-dispatcher';
16
18
  // TODO, quick fix for CSS insertion order
17
19
  import ErrorBoundary from '@docusaurus/ErrorBoundary';
@@ -21,6 +23,8 @@ export default function App() {
21
23
  <DocusaurusContextProvider>
22
24
  <BrowserContextProvider>
23
25
  <Root>
26
+ <SiteMetadataDefaults />
27
+ <SiteMetadata />
24
28
  <BaseUrlIssueBanner />
25
29
  <PendingNavigation routes={routes} delay={1000}>
26
30
  {renderRoutes(routes)}
@@ -13,7 +13,7 @@ declare type StatefulLinksCollector = LinksCollector & {
13
13
  };
14
14
  export declare const createStatefulLinksCollector: () => StatefulLinksCollector;
15
15
  export declare const useLinksCollector: () => LinksCollector;
16
- export declare function ProvideLinksCollector({ children, linksCollector, }: {
16
+ export declare function LinksCollectorProvider({ children, linksCollector, }: {
17
17
  children: ReactNode;
18
18
  linksCollector: LinksCollector;
19
19
  }): JSX.Element;
@@ -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 React, { useContext, createContext } from 'react';
7
+ import React, { useContext } from 'react';
8
8
  export const createStatefulLinksCollector = () => {
9
9
  // Set to dedup, as it's not useful to collect multiple times the same link
10
10
  const allLinks = new Set();
@@ -15,13 +15,13 @@ export const createStatefulLinksCollector = () => {
15
15
  getCollectedLinks: () => [...allLinks],
16
16
  };
17
17
  };
18
- const Context = createContext({
18
+ const Context = React.createContext({
19
19
  collectLink: () => {
20
20
  // noop by default for client
21
21
  // we only use the broken links checker server-side
22
22
  },
23
23
  });
24
24
  export const useLinksCollector = () => useContext(Context);
25
- export function ProvideLinksCollector({ children, linksCollector, }) {
25
+ export function LinksCollectorProvider({ children, linksCollector, }) {
26
26
  return <Context.Provider value={linksCollector}>{children}</Context.Provider>;
27
27
  }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ /// <reference types="react" />
8
+ export default function SiteMetadataDefaults(): JSX.Element;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ import React from 'react';
8
+ import Head from '@docusaurus/Head';
9
+ import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
10
+ import useBaseUrl from '@docusaurus/useBaseUrl';
11
+ export default function SiteMetadataDefaults() {
12
+ const { siteConfig: { favicon, tagline, title }, i18n: { currentLocale, localeConfigs }, } = useDocusaurusContext();
13
+ const faviconUrl = useBaseUrl(favicon);
14
+ const { htmlLang, direction: htmlDir } = localeConfigs[currentLocale];
15
+ return (<Head defaultTitle={`${title}${tagline ? ` · ${tagline}` : ''}`}>
16
+ <html lang={htmlLang} dir={htmlDir}/>
17
+ {favicon && <link rel="icon" href={faviconUrl}/>}
18
+ </Head>);
19
+ }
@@ -5,7 +5,7 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  import React from 'react';
8
- import { hydrate, render } from 'react-dom';
8
+ import ReactDOM from 'react-dom';
9
9
  import { BrowserRouter } from 'react-router-dom';
10
10
  import { HelmetProvider } from 'react-helmet-async';
11
11
  import routes from '@generated/routes';
@@ -21,7 +21,7 @@ if (ExecutionEnvironment.canUseDOM) {
21
21
  // first-load experience.
22
22
  // For development, there is no existing markup so we had to render it.
23
23
  // We also preload async component to avoid first-load loading screen.
24
- const renderMethod = process.env.NODE_ENV === 'production' ? hydrate : render;
24
+ const renderMethod = process.env.NODE_ENV === 'production' ? ReactDOM.hydrate : ReactDOM.render;
25
25
  preload(routes, window.location.pathname).then(() => {
26
26
  renderMethod(<HelmetProvider>
27
27
  <BrowserRouter>
@@ -18,5 +18,5 @@ Current type: ${isValidElement(children) ? 'React element' : typeof children}`);
18
18
  }
19
19
  return <>{children()}</>;
20
20
  }
21
- return fallback || null;
21
+ return fallback ?? null;
22
22
  }
@@ -10,18 +10,27 @@ import Loading from '@theme/Loading';
10
10
  import routesChunkNames from '@generated/routesChunkNames';
11
11
  import registry from '@generated/registry';
12
12
  import flat from '../flat';
13
+ import { RouteContextProvider } from '../routeContext';
13
14
  export default function ComponentCreator(path, hash) {
14
15
  // 404 page
15
16
  if (path === '*') {
16
17
  return Loadable({
17
18
  loading: Loading,
18
- loader: () => import('@theme/NotFound'),
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' } }}>
24
+ <NotFound {...props}/>
25
+ </RouteContextProvider>);
26
+ },
19
27
  });
20
28
  }
21
29
  const chunkNamesKey = `${path}-${hash}`;
22
30
  const chunkNames = routesChunkNames[chunkNamesKey];
23
31
  const optsModules = [];
24
32
  const optsWebpack = [];
33
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
25
34
  const optsLoader = {};
26
35
  /* Prepare opts data that react-loadable needs
27
36
  https://github.com/jamiebuilds/react-loadable#declaring-which-modules-are-being-loaded
@@ -38,8 +47,8 @@ export default function ComponentCreator(path, hash) {
38
47
  ]
39
48
  */
40
49
  const flatChunkNames = flat(chunkNames);
41
- Object.keys(flatChunkNames).forEach((key) => {
42
- const chunkRegistry = registry[flatChunkNames[key]];
50
+ Object.entries(flatChunkNames).forEach(([key, chunkName]) => {
51
+ const chunkRegistry = registry[chunkName];
43
52
  if (chunkRegistry) {
44
53
  // eslint-disable-next-line prefer-destructuring
45
54
  optsLoader[key] = chunkRegistry[0];
@@ -56,23 +65,34 @@ export default function ComponentCreator(path, hash) {
56
65
  // Clone the original object since we don't want to alter the original.
57
66
  const loadedModules = JSON.parse(JSON.stringify(chunkNames));
58
67
  Object.keys(loaded).forEach((key) => {
59
- let val = loadedModules;
60
- const keyPath = key.split('.');
61
- for (let i = 0; i < keyPath.length - 1; i += 1) {
62
- val = val[keyPath[i]];
68
+ const newComp = loaded[key].default;
69
+ if (!newComp) {
70
+ 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.`);
63
71
  }
64
- val[keyPath[keyPath.length - 1]] = loaded[key].default;
65
- const nonDefaultKeys = Object.keys(loaded[key]).filter((k) => k !== 'default');
66
- if (nonDefaultKeys && nonDefaultKeys.length) {
67
- nonDefaultKeys.forEach((nonDefaultKey) => {
68
- val[keyPath[keyPath.length - 1]][nonDefaultKey] =
69
- loaded[key][nonDefaultKey];
72
+ if (typeof newComp === 'object' || typeof newComp === 'function') {
73
+ Object.keys(loaded[key])
74
+ .filter((k) => k !== 'default')
75
+ .forEach((nonDefaultKey) => {
76
+ newComp[nonDefaultKey] = loaded[key][nonDefaultKey];
70
77
  });
71
78
  }
79
+ let val = loadedModules;
80
+ const keyPath = key.split('.');
81
+ keyPath.slice(0, -1).forEach((k) => {
82
+ val = val[k];
83
+ });
84
+ val[keyPath[keyPath.length - 1]] = newComp;
72
85
  });
73
86
  const Component = loadedModules.component;
74
87
  delete loadedModules.component;
75
- return <Component {...loadedModules} {...props}/>;
88
+ /* eslint-disable no-underscore-dangle */
89
+ const routeContextModule = loadedModules.__routeContextModule;
90
+ delete loadedModules.__routeContextModule;
91
+ /* eslint-enable no-underscore-dangle */
92
+ // Is there any way to put this RouteContextProvider upper in the tree?
93
+ return (<RouteContextProvider value={routeContextModule}>
94
+ <Component {...loadedModules} {...props}/>
95
+ </RouteContextProvider>);
76
96
  },
77
97
  });
78
98
  }
@@ -9,4 +9,4 @@ import { type ReactNode } from 'react';
9
9
  import type { InterpolateProps, InterpolateValues } from '@docusaurus/Interpolate';
10
10
  export declare function interpolate<Str extends string>(text: Str, values?: InterpolateValues<Str, string | number>): string;
11
11
  export declare function interpolate<Str extends string, Value extends ReactNode>(text: Str, values?: InterpolateValues<Str, Value>): ReactNode;
12
- export default function Interpolate<Str extends string>({ children, values, }: InterpolateProps<Str>): ReactNode;
12
+ export default function Interpolate<Str extends string>({ children, values, }: InterpolateProps<Str>): JSX.Element;
@@ -4,13 +4,13 @@
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 React from 'react';
7
+ import React, { isValidElement } from 'react';
8
8
  /*
9
9
  Minimal implementation of a React interpolate component.
10
10
  We don't ship a markdown parser nor a feature-complete i18n library on purpose.
11
11
  More details here: https://github.com/facebook/docusaurus/pull/4295
12
12
  */
13
- const ValueRegexp = /{\w+}/g;
13
+ const ValueRegexp = /\{\w+\}/g;
14
14
  const ValueFoundMarker = '{}'; // does not care much
15
15
  export function interpolate(text, values) {
16
16
  const elements = [];
@@ -19,7 +19,7 @@ export function interpolate(text, values) {
19
19
  const key = match.substring(1, match.length - 1);
20
20
  const value = values?.[key];
21
21
  if (typeof value !== 'undefined') {
22
- const element = React.isValidElement(value)
22
+ const element = isValidElement(value)
23
23
  ? value
24
24
  : // For non-React elements: basic primitive->string conversion
25
25
  String(value);
@@ -52,5 +52,5 @@ export default function Interpolate({ children, values, }) {
52
52
  console.warn('Illegal <Interpolate> children', children);
53
53
  throw new Error('The Docusaurus <Interpolate> component only accept simple string values');
54
54
  }
55
- return interpolate(children, values);
55
+ return <>{interpolate(children, values)}</>;
56
56
  }
@@ -19,5 +19,5 @@ declare const _default: React.ForwardRefExoticComponent<Pick<Partial<import("rea
19
19
  readonly href?: string | undefined;
20
20
  readonly autoAddBaseUrl?: boolean | undefined;
21
21
  readonly 'data-noBrokenLinkCheck'?: boolean | undefined;
22
- }, "children" | "replace" | "slot" | "style" | "title" | "component" | "location" | "exact" | "sensitive" | "strict" | "id" | "dir" | "rel" | "href" | "type" | "key" | "isNavLink" | "className" | "to" | "innerRef" | "download" | "hrefLang" | "media" | "ping" | "target" | "referrerPolicy" | "defaultChecked" | "defaultValue" | "suppressContentEditableWarning" | "suppressHydrationWarning" | "accessKey" | "contentEditable" | "contextMenu" | "draggable" | "hidden" | "lang" | "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>>;
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>>;
23
23
  export default _default;
@@ -110,7 +110,7 @@ function Link({ isNavLink, to, href, activeClassName, isActive, 'data-noBrokenLi
110
110
  return isRegularHtmlLink ? (
111
111
  // eslint-disable-next-line jsx-a11y/anchor-has-content
112
112
  <a ref={innerRef} href={targetLink} {...(targetLinkUnprefixed &&
113
- !isInternal && { target: '_blank', rel: 'noopener noreferrer' })} {...props}/>) : (<LinkComponent {...props} onMouseEnter={onMouseEnter} innerRef={handleRef} to={targetLink || ''}
113
+ !isInternal && { target: '_blank', rel: 'noopener noreferrer' })} {...props}/>) : (<LinkComponent {...props} onMouseEnter={onMouseEnter} innerRef={handleRef} to={targetLink}
114
114
  // avoid "React does not recognize the `activeClassName` prop on a DOM
115
115
  // element"
116
116
  {...(isNavLink && { isActive, activeClassName })}/>);
@@ -5,8 +5,8 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  /// <reference types="@docusaurus/module-type-aliases" />
8
- import type { ReactNode } from 'react';
8
+ /// <reference types="react" />
9
9
  import { type InterpolateValues } from '@docusaurus/Interpolate';
10
10
  import type { TranslateParam, TranslateProps } from '@docusaurus/Translate';
11
11
  export declare function translate<Str extends string>({ message, id }: TranslateParam<Str>, values?: InterpolateValues<Str, string | number>): string;
12
- export default function Translate<Str extends string>({ children, id, values, }: TranslateProps<Str>): ReactNode;
12
+ export default function Translate<Str extends string>({ children, id, values, }: TranslateProps<Str>): JSX.Element;
@@ -4,6 +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 React from 'react';
7
8
  import { interpolate } from '@docusaurus/Interpolate';
8
9
  // Can't read it from context, due to exposing imperative API
9
10
  import codeTranslations from '@generated/codeTranslations';
@@ -29,5 +30,5 @@ export default function Translate({ children, id, values, }) {
29
30
  throw new Error('The Docusaurus <Translate> component only accept simple string values');
30
31
  }
31
32
  const localizedMessage = getLocalizedMessage({ message: children, id });
32
- return interpolate(localizedMessage, values);
33
+ return <>{interpolate(localizedMessage, values)}</>;
33
34
  }
@@ -21,6 +21,11 @@ function addBaseUrl(siteUrl, baseUrl, url, { forcePrependBaseUrl = false, absolu
21
21
  if (forcePrependBaseUrl) {
22
22
  return baseUrl + url.replace(/^\//, '');
23
23
  }
24
+ // /baseUrl -> /baseUrl/
25
+ // https://github.com/facebook/docusaurus/issues/6315
26
+ if (url === baseUrl.replace(/\/$/, '')) {
27
+ return baseUrl;
28
+ }
24
29
  // We should avoid adding the baseurl twice if it's already there
25
30
  const shouldAddBaseUrl = !url.startsWith(baseUrl);
26
31
  const basePath = shouldAddBaseUrl ? baseUrl + url.replace(/^\//, '') : url;
@@ -5,7 +5,7 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  import { useContext } from 'react';
8
- import { Context } from './docusaurusContext';
8
+ import { Context } from '../docusaurusContext';
9
9
  export default function useDocusaurusContext() {
10
10
  return useContext(Context);
11
11
  }
@@ -4,6 +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
- export default function useGlobalData(): Record<string, unknown>;
8
- export declare function useAllPluginInstancesData<T = unknown>(pluginName: string): Record<string, T>;
9
- export declare function usePluginData<T = unknown>(pluginName: string, pluginId?: string): T;
7
+ import type { GlobalData } from '@docusaurus/types';
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];
@@ -5,7 +5,7 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  import { useContext } from 'react';
8
- import { Context } from './browserContext';
8
+ import { Context } from '../browserContext';
9
9
  export default function useIsBrowser() {
10
10
  return useContext(Context);
11
11
  }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ import type { PluginRouteContext } from '@docusaurus/types';
8
+ export default function useRouteContext(): PluginRouteContext;
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ import React from 'react';
8
+ import { Context } from '../routeContext';
9
+ export default function useRouteContext() {
10
+ const context = React.useContext(Context);
11
+ if (!context) {
12
+ throw new Error('Unexpected: no Docusaurus route context found');
13
+ }
14
+ return context;
15
+ }
@@ -5,4 +5,6 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  import type { RouteChunksTree } from '@docusaurus/types';
8
- export default function flat(target: RouteChunksTree): Record<string, string>;
8
+ export default function flat(target: RouteChunksTree): {
9
+ [keyPath: string]: string;
10
+ };
@@ -9,8 +9,7 @@ export default function flat(target) {
9
9
  const delimiter = '.';
10
10
  const output = {};
11
11
  function step(object, prefix) {
12
- Object.keys(object).forEach((key) => {
13
- const value = object[key];
12
+ Object.entries(object).forEach(([key, value]) => {
14
13
  const newKey = prefix ? `${prefix}${delimiter}${key}` : key;
15
14
  if (isTree(value)) {
16
15
  step(value, newKey);
@@ -13,11 +13,7 @@ export default function normalizeLocation(location) {
13
13
  pathname: pathnames[location.pathname],
14
14
  };
15
15
  }
16
- let pathname = location.pathname || '/';
17
- pathname = pathname.trim().replace(/\/index\.html$/, '');
18
- if (pathname === '') {
19
- pathname = '/';
20
- }
16
+ const pathname = location.pathname.trim().replace(/\/index\.html$/, '') || '/';
21
17
  pathnames[location.pathname] = pathname;
22
18
  return {
23
19
  ...location,
@@ -30,9 +30,9 @@ function linkPrefetchStrategy(url) {
30
30
  link.setAttribute('href', url);
31
31
  link.onload = resolve;
32
32
  link.onerror = reject;
33
- const parentElement = document.getElementsByTagName('head')[0] ||
34
- document.getElementsByName('script')[0].parentNode;
35
- parentElement.appendChild(link);
33
+ const parentElement = document.getElementsByTagName('head')[0] ??
34
+ document.getElementsByName('script')[0]?.parentNode;
35
+ parentElement?.appendChild(link);
36
36
  });
37
37
  }
38
38
  function xhrPrefetchStrategy(url) {
@@ -16,13 +16,7 @@ import { matchRoutes } from 'react-router-config';
16
16
  */
17
17
  export default function preload(routes, pathname) {
18
18
  const matches = matchRoutes(routes, pathname);
19
- return Promise.all(matches.map((match) => {
20
- const { component } = match.route;
21
- // @ts-expect-error: ComponentCreator injected this method.
22
- if (component && component.preload) {
23
- // @ts-expect-error: checked above.
24
- return component.preload();
25
- }
26
- return undefined;
27
- }));
19
+ return Promise.all(
20
+ // @ts-expect-error: ComponentCreator injected this method.
21
+ matches.map((match) => match.route.component?.preload?.()));
28
22
  }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ import React, { type ReactNode } from 'react';
8
+ import type { PluginRouteContext, RouteContext } from '@docusaurus/types';
9
+ export declare const Context: React.Context<PluginRouteContext | null>;
10
+ export declare function RouteContextProvider({ children, value, }: {
11
+ children: ReactNode;
12
+ value: PluginRouteContext | RouteContext | null;
13
+ }): JSX.Element;
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ import React, { useMemo } from 'react';
8
+ export const Context = React.createContext(null);
9
+ function mergeContexts({ parent, value, }) {
10
+ if (!parent) {
11
+ if (!value) {
12
+ throw new Error('Unexpected: no Docusaurus route context found');
13
+ }
14
+ else if (!('plugin' in value)) {
15
+ throw new Error('Unexpected: Docusaurus topmost route context has no `plugin` attribute');
16
+ }
17
+ return value;
18
+ }
19
+ // TODO deep merge this
20
+ const data = { ...parent.data, ...value?.data };
21
+ return {
22
+ // nested routes are not supposed to override plugin attribute
23
+ plugin: parent.plugin,
24
+ data,
25
+ };
26
+ }
27
+ export function RouteContextProvider({ children, value, }) {
28
+ const parent = React.useContext(Context);
29
+ const mergedValue = useMemo(() => mergeContexts({ parent, value }), [parent, value]);
30
+ return <Context.Provider value={mergedValue}>{children}</Context.Provider>;
31
+ }