@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
@@ -17,7 +17,7 @@ import fs from 'fs-extra';
17
17
  import routes from '@generated/routes';
18
18
  import preload from './preload';
19
19
  import App from './App';
20
- import { createStatefulLinksCollector, ProvideLinksCollector, } from './LinksCollector';
20
+ import { createStatefulLinksCollector, LinksCollectorProvider, } from './LinksCollector';
21
21
  import logger from '@docusaurus/logger';
22
22
  // eslint-disable-next-line no-restricted-imports
23
23
  import _ from 'lodash';
@@ -57,9 +57,9 @@ async function doRender(locals) {
57
57
  const appHtml = ReactDOMServer.renderToString(<Loadable.Capture report={(moduleName) => modules.add(moduleName)}>
58
58
  <HelmetProvider context={helmetContext}>
59
59
  <StaticRouter location={location} context={context}>
60
- <ProvideLinksCollector linksCollector={linksCollector}>
60
+ <LinksCollectorProvider linksCollector={linksCollector}>
61
61
  <App />
62
- </ProvideLinksCollector>
62
+ </LinksCollectorProvider>
63
63
  </StaticRouter>
64
64
  </HelmetProvider>
65
65
  </Loadable.Capture>);
@@ -81,13 +81,13 @@ async function doRender(locals) {
81
81
  // manifest information.
82
82
  const modulesToBeLoaded = [...manifest.entrypoints, ...Array.from(modules)];
83
83
  const bundles = getBundles(manifest, modulesToBeLoaded);
84
- const stylesheets = (bundles.css || []).map((b) => b.file);
85
- const scripts = (bundles.js || []).map((b) => b.file);
84
+ const stylesheets = (bundles.css ?? []).map((b) => b.file);
85
+ const scripts = (bundles.js ?? []).map((b) => b.file);
86
86
  const renderedHtml = renderSSRTemplate(ssrTemplate, {
87
87
  appHtml,
88
88
  baseUrl,
89
- htmlAttributes: htmlAttributes || '',
90
- bodyAttributes: bodyAttributes || '',
89
+ htmlAttributes,
90
+ bodyAttributes,
91
91
  headTags,
92
92
  preBodyTags,
93
93
  postBodyTags,
@@ -7,6 +7,7 @@
7
7
  import React from 'react';
8
8
  import Layout from '@theme/Layout';
9
9
  import ErrorBoundary from '@docusaurus/ErrorBoundary';
10
+ import Head from '@docusaurus/Head';
10
11
  function ErrorDisplay({ error, tryAgain }) {
11
12
  return (<div style={{
12
13
  display: 'flex',
@@ -32,7 +33,10 @@ export default function Error({ error, tryAgain }) {
32
33
  // Note: we display the original error here, not the error that we
33
34
  // captured in this extra error boundary
34
35
  fallback={() => <ErrorDisplay error={error} tryAgain={tryAgain}/>}>
35
- <Layout title="Page Error">
36
+ <Head>
37
+ <title>Page Error</title>
38
+ </Head>
39
+ <Layout>
36
40
  <ErrorDisplay error={error} tryAgain={tryAgain}/>
37
41
  </Layout>
38
42
  </ErrorBoundary>);
@@ -7,4 +7,4 @@
7
7
  /// <reference types="@docusaurus/module-type-aliases" />
8
8
  /// <reference types="react" />
9
9
  import type { Props } from '@theme/Layout';
10
- export default function Layout({ children, title, description, }: Props): JSX.Element;
10
+ export default function Layout({ children }: Props): JSX.Element;
@@ -5,21 +5,6 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
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 Layout({ children, title, description, }) {
12
- const context = useDocusaurusContext();
13
- const { siteConfig } = context;
14
- const { favicon, tagline, title: defaultTitle } = siteConfig;
15
- const faviconUrl = useBaseUrl(favicon);
16
- return (<>
17
- <Head defaultTitle={`${defaultTitle}${tagline ? ` · ${tagline}` : ''}`}>
18
- {title && <title>{`${title} · ${tagline}`}</title>}
19
- {favicon && <link rel="icon" href={faviconUrl}/>}
20
- {description && <meta name="description" content={description}/>}
21
- {description && (<meta property="og:description" content={description}/>)}
22
- </Head>
23
- {children}
24
- </>);
8
+ export default function Layout({ children }) {
9
+ return <>{children}</>;
25
10
  }
@@ -6,16 +6,22 @@
6
6
  */
7
7
  import React from 'react';
8
8
  import Layout from '@theme/Layout';
9
+ import Head from '@docusaurus/Head';
9
10
  export default function NotFound() {
10
- return (<Layout title="Page Not Found">
11
- <div style={{
11
+ return (<>
12
+ <Head>
13
+ <title>Page Not Found</title>
14
+ </Head>
15
+ <Layout>
16
+ <div style={{
12
17
  display: 'flex',
13
18
  justifyContent: 'center',
14
19
  alignItems: 'center',
15
20
  height: '50vh',
16
21
  fontSize: '20px',
17
22
  }}>
18
- <h1>Oops, page not found </h1>
19
- </div>
20
- </Layout>);
23
+ <h1>Oops, page not found </h1>
24
+ </div>
25
+ </Layout>
26
+ </>);
21
27
  }
@@ -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 { ReactNode } from 'react';
8
- export default function Root({ children }: {
9
- children: ReactNode;
10
- }): ReactNode;
7
+ /// <reference types="@docusaurus/module-type-aliases" />
8
+ /// <reference types="react" />
9
+ import type { Props } from '@theme/Root';
10
+ export default function Root({ children }: Props): 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
  // Wrapper at the very top of the app, that is applied constantly
8
9
  // and does not depend on current route (unlike the layout)
9
10
  //
@@ -12,5 +13,5 @@
12
13
  //
13
14
  // See https://github.com/facebook/docusaurus/issues/3919
14
15
  export default function Root({ children }) {
15
- return children;
16
+ return <>{children}</>;
16
17
  }
@@ -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 SiteMetadata(): JSX.Element | null;
@@ -0,0 +1,10 @@
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
+ // To be implemented by the theme with <Head>
8
+ export default function SiteMetadata() {
9
+ return null;
10
+ }
@@ -123,7 +123,7 @@ async function buildLocale({ siteDir, locale, cliOptions, forceTerminate, isLast
123
123
  plugins.forEach((plugin) => {
124
124
  const { configureWebpack, configurePostCss } = plugin;
125
125
  if (configurePostCss) {
126
- clientConfig = (0, utils_1.applyConfigurePostCss)(configurePostCss, clientConfig);
126
+ clientConfig = (0, utils_1.applyConfigurePostCss)(configurePostCss.bind(plugin), clientConfig);
127
127
  }
128
128
  if (configureWebpack) {
129
129
  clientConfig = (0, utils_1.applyConfigureWebpack)(configureWebpack.bind(plugin), // The plugin lifecycle may reference `this`.
@@ -11,7 +11,7 @@ const tslib_1 = require("tslib");
11
11
  const choosePort_1 = tslib_1.__importDefault(require("../choosePort"));
12
12
  const utils_1 = require("@docusaurus/utils");
13
13
  function getCLIOptionHost(hostOption) {
14
- return hostOption || 'localhost';
14
+ return hostOption ?? 'localhost';
15
15
  }
16
16
  exports.getCLIOptionHost = getCLIOptionHost;
17
17
  async function getCLIOptionPort(portOption, host) {
@@ -5,7 +5,4 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  import type { BuildCLIOptions } from '@docusaurus/types';
8
- export declare function buildSshUrl(githubHost: string, organizationName: string, projectName: string, githubPort?: string): string;
9
- export declare function buildHttpsUrl(gitCredentials: string, githubHost: string, organizationName: string, projectName: string, githubPort?: string): string;
10
- export declare function hasSSHProtocol(sourceRepoUrl: string): boolean;
11
8
  export default function deploy(siteDir: string, cliOptions?: Partial<BuildCLIOptions>): Promise<void>;
@@ -6,11 +6,11 @@
6
6
  * LICENSE file in the root directory of this source tree.
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.hasSSHProtocol = exports.buildHttpsUrl = exports.buildSshUrl = void 0;
10
9
  const tslib_1 = require("tslib");
11
10
  const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
12
11
  const shelljs_1 = tslib_1.__importDefault(require("shelljs"));
13
12
  const logger_1 = tslib_1.__importDefault(require("@docusaurus/logger"));
13
+ const utils_1 = require("@docusaurus/utils");
14
14
  const server_1 = require("../server");
15
15
  const build_1 = tslib_1.__importDefault(require("./build"));
16
16
  const path_1 = tslib_1.__importDefault(require("path"));
@@ -33,33 +33,6 @@ function shellExecLog(cmd) {
33
33
  throw err;
34
34
  }
35
35
  }
36
- function buildSshUrl(githubHost, organizationName, projectName, githubPort) {
37
- if (githubPort) {
38
- return `ssh://git@${githubHost}:${githubPort}/${organizationName}/${projectName}.git`;
39
- }
40
- return `git@${githubHost}:${organizationName}/${projectName}.git`;
41
- }
42
- exports.buildSshUrl = buildSshUrl;
43
- function buildHttpsUrl(gitCredentials, githubHost, organizationName, projectName, githubPort) {
44
- if (githubPort) {
45
- return `https://${gitCredentials}@${githubHost}:${githubPort}/${organizationName}/${projectName}.git`;
46
- }
47
- return `https://${gitCredentials}@${githubHost}/${organizationName}/${projectName}.git`;
48
- }
49
- exports.buildHttpsUrl = buildHttpsUrl;
50
- function hasSSHProtocol(sourceRepoUrl) {
51
- try {
52
- if (new URL(sourceRepoUrl).protocol === 'ssh:') {
53
- return true;
54
- }
55
- return false;
56
- }
57
- catch {
58
- // Fails when there isn't a protocol
59
- return /^(?:[\w-]+@)?[\w.-]+:[\w./_-]+/.test(sourceRepoUrl); // git@github.com:facebook/docusaurus.git
60
- }
61
- }
62
- exports.hasSSHProtocol = hasSSHProtocol;
63
36
  async function deploy(siteDir, cliOptions = {}) {
64
37
  const { outDir, siteConfig, siteConfigPath } = await (0, server_1.loadContext)(siteDir, {
65
38
  customConfigFilePath: cliOptions.config,
@@ -87,7 +60,7 @@ This behavior can have SEO impacts and create relative link issues.
87
60
  process.env.USE_SSH.toLowerCase() === 'true';
88
61
  if (!gitUser && !useSSH) {
89
62
  // If USE_SSH is unspecified: try inferring from repo URL
90
- if (process.env.USE_SSH === undefined && hasSSHProtocol(sourceRepoUrl)) {
63
+ if (process.env.USE_SSH === undefined && (0, utils_1.hasSSHProtocol)(sourceRepoUrl)) {
91
64
  useSSH = true;
92
65
  }
93
66
  else {
@@ -132,12 +105,12 @@ You can also set the deploymentBranch property in docusaurus.config.js .`);
132
105
  const githubPort = process.env.GITHUB_PORT || siteConfig.githubPort;
133
106
  let deploymentRepoURL;
134
107
  if (useSSH) {
135
- deploymentRepoURL = buildSshUrl(githubHost, organizationName, projectName, githubPort);
108
+ deploymentRepoURL = (0, utils_1.buildSshUrl)(githubHost, organizationName, projectName, githubPort);
136
109
  }
137
110
  else {
138
111
  const gitPass = process.env.GIT_PASS;
139
112
  const gitCredentials = gitPass ? `${gitUser}:${gitPass}` : gitUser;
140
- deploymentRepoURL = buildHttpsUrl(gitCredentials, githubHost, organizationName, projectName, githubPort);
113
+ deploymentRepoURL = (0, utils_1.buildHttpsUrl)(gitCredentials, githubHost, organizationName, projectName, githubPort);
141
114
  }
142
115
  logger_1.default.info `Remote repo URL: name=${obfuscateGitPass(deploymentRepoURL)}`;
143
116
  // Check if this is a cross-repo publish.
@@ -15,11 +15,7 @@ async function externalCommand(cli, siteDir) {
15
15
  const plugins = await (0, init_1.default)({ pluginConfigs, context });
16
16
  // Plugin Lifecycle - extendCli.
17
17
  plugins.forEach((plugin) => {
18
- const { extendCli } = plugin;
19
- if (!extendCli) {
20
- return;
21
- }
22
- extendCli(cli);
18
+ plugin.extendCli?.(cli);
23
19
  });
24
20
  }
25
21
  exports.default = externalCommand;
@@ -60,17 +60,16 @@ async function start(siteDir, cliOptions) {
60
60
  logger_1.default.error(err.stack);
61
61
  });
62
62
  }, 500);
63
- const { siteConfig, plugins = [] } = props;
63
+ const { siteConfig, plugins } = props;
64
64
  const normalizeToSiteDir = (filepath) => {
65
65
  if (filepath && path_1.default.isAbsolute(filepath)) {
66
66
  return (0, utils_1.posixPath)(path_1.default.relative(siteDir, filepath));
67
67
  }
68
68
  return (0, utils_1.posixPath)(filepath);
69
69
  };
70
- const pluginPaths = []
71
- .concat(...plugins
72
- .map((plugin) => plugin.getPathsToWatch?.() ?? [])
73
- .filter(Boolean))
70
+ const pluginPaths = plugins
71
+ .flatMap((plugin) => plugin.getPathsToWatch?.() ?? [])
72
+ .filter(Boolean)
74
73
  .map(normalizeToSiteDir);
75
74
  const pathsToWatch = [
76
75
  ...pluginPaths,
@@ -101,7 +100,7 @@ async function start(siteDir, cliOptions) {
101
100
  plugins: [
102
101
  // Generates an `index.html` file with the <script> injected.
103
102
  new html_webpack_plugin_1.default({
104
- template: path_1.default.resolve(__dirname, '../webpack/templates/index.html.template.ejs'),
103
+ template: path_1.default.join(__dirname, '../webpack/templates/index.html.template.ejs'),
105
104
  // So we can define the position where the scripts are injected.
106
105
  inject: false,
107
106
  filename: 'index.html',
@@ -116,10 +115,10 @@ async function start(siteDir, cliOptions) {
116
115
  plugins.forEach((plugin) => {
117
116
  const { configureWebpack, configurePostCss } = plugin;
118
117
  if (configurePostCss) {
119
- config = (0, utils_2.applyConfigurePostCss)(configurePostCss, config);
118
+ config = (0, utils_2.applyConfigurePostCss)(configurePostCss.bind(plugin), config);
120
119
  }
121
120
  if (configureWebpack) {
122
- config = (0, utils_2.applyConfigureWebpack)(configureWebpack.bind(plugin), // The plugin lifecycle may reference `this`. // TODO remove this implicit api: inject in callback instead
121
+ config = (0, utils_2.applyConfigureWebpack)(configureWebpack.bind(plugin), // The plugin lifecycle may reference `this`.
123
122
  config, false, props.siteConfig.webpack?.jsLoader, plugin.content);
124
123
  }
125
124
  });
@@ -95,8 +95,7 @@ export default function ${wrapperComponentName}(props) {
95
95
  );
96
96
  }
97
97
  `;
98
- await fs_extra_1.default.ensureDir(path_1.default.dirname(toPath));
99
- await fs_extra_1.default.writeFile(toPath, content);
98
+ await fs_extra_1.default.outputFile(toPath, content);
100
99
  return { createdFiles: [toPath] };
101
100
  }
102
101
  exports.wrap = wrap;
@@ -8,18 +8,16 @@
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.initSwizzleContext = void 0;
10
10
  const tslib_1 = require("tslib");
11
- const module_1 = require("module");
12
11
  const server_1 = require("../../server");
13
12
  const init_1 = tslib_1.__importStar(require("../../server/plugins/init"));
14
13
  async function initSwizzleContext(siteDir) {
15
14
  const context = await (0, server_1.loadContext)(siteDir);
16
- const pluginRequire = (0, module_1.createRequire)(context.siteConfigPath);
17
15
  const pluginConfigs = await (0, server_1.loadPluginConfigs)(context);
18
16
  const plugins = await (0, init_1.default)({
19
17
  pluginConfigs,
20
18
  context,
21
19
  });
22
- const pluginsNormalized = await (0, init_1.normalizePluginConfigs)(pluginConfigs, pluginRequire);
20
+ const pluginsNormalized = await (0, init_1.normalizePluginConfigs)(pluginConfigs, context.siteConfigPath);
23
21
  return {
24
22
  plugins: plugins.map((plugin, pluginIndex) => ({
25
23
  plugin: pluginsNormalized[pluginIndex],
@@ -31,8 +31,7 @@ This component is safe to swizzle and was designed for this purpose.
31
31
  The swizzled component is retro-compatible with minor version upgrades.
32
32
  `,
33
33
  ],
34
- });
35
- table.push({
34
+ }, {
36
35
  [tableStatusLabel('unsafe')]: [
37
36
  logger_1.default.code('--danger'),
38
37
  `
@@ -44,12 +43,11 @@ ${logger_1.default.green('Tip')}: your customization can't be done in a ${tableS
44
43
  Report it here: https://github.com/facebook/docusaurus/discussions/5468
45
44
  `,
46
45
  ],
47
- });
48
- table.push({
46
+ }, {
49
47
  [tableStatusLabel('forbidden')]: [
50
48
  '',
51
49
  `
52
- This component should not meant to be swizzled.
50
+ This component is not meant to be swizzled.
53
51
  `,
54
52
  ],
55
53
  });
@@ -66,18 +64,17 @@ function actionsTable() {
66
64
  Creates a wrapper around the original theme component.
67
65
  Allows rendering other components before/after the original theme component.
68
66
 
69
- ${logger_1.default.green('Tip')}: prefer ${logger_1.default.code('--wrap')} whenever possible to reduces the amount of code to maintain.
67
+ ${logger_1.default.green('Tip')}: prefer ${logger_1.default.code('--wrap')} whenever possible to reduce the amount of code to maintain.
70
68
  `,
71
69
  ],
72
- });
73
- table.push({
70
+ }, {
74
71
  [logger_1.default.bold('Eject')]: [
75
72
  logger_1.default.code('--eject'),
76
73
  `
77
74
  Ejects the full source code of the original theme component.
78
- Allows overriding the original component entirely with your own UI and logic.
75
+ Allows overriding of the original component entirely with your own UI and logic.
79
76
 
80
- ${logger_1.default.green('Tip')}: ${logger_1.default.code('--eject')} can be useful to completely redesign a component.
77
+ ${logger_1.default.green('Tip')}: ${logger_1.default.code('--eject')} can be useful for completely redesigning a component.
81
78
  `,
82
79
  ],
83
80
  });
@@ -9,6 +9,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.getThemePath = exports.getThemeName = exports.getThemeNames = exports.getPluginByThemeName = exports.pluginToThemeName = void 0;
10
10
  const tslib_1 = require("tslib");
11
11
  const logger_1 = tslib_1.__importDefault(require("@docusaurus/logger"));
12
+ const path_1 = tslib_1.__importDefault(require("path"));
12
13
  const leven_1 = tslib_1.__importDefault(require("leven"));
13
14
  const lodash_1 = tslib_1.__importDefault(require("lodash"));
14
15
  const prompts_1 = require("./prompts");
@@ -87,8 +88,10 @@ exports.getThemeName = getThemeName;
87
88
  function getThemePath({ plugins, themeName, typescript, }) {
88
89
  const pluginInstance = getPluginByThemeName(plugins, themeName);
89
90
  const themePath = typescript
90
- ? pluginInstance.instance.getTypeScriptThemePath?.()
91
- : pluginInstance.instance.getThemePath?.();
91
+ ? pluginInstance.instance.getTypeScriptThemePath &&
92
+ path_1.default.resolve(pluginInstance.instance.path, pluginInstance.instance.getTypeScriptThemePath())
93
+ : pluginInstance.instance.getThemePath &&
94
+ path_1.default.resolve(pluginInstance.instance.path, pluginInstance.instance.getThemePath());
92
95
  if (!themePath) {
93
96
  logger_1.default.warn(typescript
94
97
  ? logger_1.default.interpolate `name=${themeName} does not provide TypeScript theme code via ${'getTypeScriptThemePath()'}.`
@@ -4,12 +4,5 @@
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 Slugger } from '@docusaurus/utils';
8
- declare type Options = {
9
- maintainCase?: boolean;
10
- overwrite?: boolean;
11
- };
12
- export declare function transformMarkdownHeadingLine(line: string, slugger: Slugger, options?: Options): string;
13
- export declare function transformMarkdownContent(content: string, options?: Options): string;
14
- export default function writeHeadingIds(siteDir: string, files?: string[], options?: Options): Promise<void>;
15
- export {};
7
+ import { type WriteHeadingIDOptions } from '@docusaurus/utils';
8
+ export default function writeHeadingIds(siteDir: string, files?: string[], options?: WriteHeadingIDOptions): Promise<void>;
@@ -6,71 +6,16 @@
6
6
  * LICENSE file in the root directory of this source tree.
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.transformMarkdownContent = exports.transformMarkdownHeadingLine = void 0;
10
9
  const tslib_1 = require("tslib");
11
10
  const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
12
11
  const logger_1 = tslib_1.__importDefault(require("@docusaurus/logger"));
12
+ const utils_1 = require("@docusaurus/utils");
13
13
  const server_1 = require("../server");
14
14
  const init_1 = tslib_1.__importDefault(require("../server/plugins/init"));
15
- const utils_1 = require("@docusaurus/utils");
16
15
  const utils_2 = require("../server/utils");
17
- function unwrapMarkdownLinks(line) {
18
- return line.replace(/\[(?<alt>[^\]]+)\]\([^)]+\)/g, (match, p1) => p1);
19
- }
20
- function addHeadingId(line, slugger, maintainCase) {
21
- let headingLevel = 0;
22
- while (line.charAt(headingLevel) === '#') {
23
- headingLevel += 1;
24
- }
25
- const headingText = line.slice(headingLevel).trimEnd();
26
- const headingHashes = line.slice(0, headingLevel);
27
- const slug = slugger
28
- .slug(unwrapMarkdownLinks(headingText).trim(), { maintainCase })
29
- .replace(/^-+/, '')
30
- .replace(/-+$/, '');
31
- return `${headingHashes}${headingText} {#${slug}}`;
32
- }
33
- function transformMarkdownHeadingLine(line, slugger, options = { maintainCase: false, overwrite: false }) {
34
- const { maintainCase = false, overwrite = false } = options;
35
- if (!line.startsWith('#')) {
36
- throw new Error(`Line is not a Markdown heading: ${line}.`);
37
- }
38
- const parsedHeading = (0, utils_1.parseMarkdownHeadingId)(line);
39
- // Do not process if id is already there
40
- if (parsedHeading.id && !overwrite) {
41
- return line;
42
- }
43
- return addHeadingId(parsedHeading.text, slugger, maintainCase);
44
- }
45
- exports.transformMarkdownHeadingLine = transformMarkdownHeadingLine;
46
- function transformMarkdownLine(line, slugger, options) {
47
- // Ignore h1 headings on purpose, as we don't create anchor links for those
48
- if (line.startsWith('##')) {
49
- return transformMarkdownHeadingLine(line, slugger, options);
50
- }
51
- return line;
52
- }
53
- function transformMarkdownLines(lines, options) {
54
- let inCode = false;
55
- const slugger = (0, utils_1.createSlugger)();
56
- return lines.map((line) => {
57
- if (line.startsWith('```')) {
58
- inCode = !inCode;
59
- return line;
60
- }
61
- if (inCode) {
62
- return line;
63
- }
64
- return transformMarkdownLine(line, slugger, options);
65
- });
66
- }
67
- function transformMarkdownContent(content, options) {
68
- return transformMarkdownLines(content.split('\n'), options).join('\n');
69
- }
70
- exports.transformMarkdownContent = transformMarkdownContent;
71
16
  async function transformMarkdownFile(filepath, options) {
72
17
  const content = await fs_extra_1.default.readFile(filepath, 'utf8');
73
- const updatedContent = transformMarkdownLines(content.split('\n'), options).join('\n');
18
+ const updatedContent = (0, utils_1.writeMarkdownHeadingId)(content, options);
74
19
  if (content !== updatedContent) {
75
20
  await fs_extra_1.default.writeFile(filepath, updatedContent);
76
21
  return filepath;
@@ -5,25 +5,12 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  import type { RouteConfig, ReportingSeverity } from '@docusaurus/types';
8
- declare type BrokenLink = {
9
- link: string;
10
- resolvedLink: string;
11
- };
12
- export declare function getAllBrokenLinks({ allCollectedLinks, routes, }: {
13
- allCollectedLinks: Record<string, string[]>;
14
- routes: RouteConfig[];
15
- }): Record<string, BrokenLink[]>;
16
- export declare function getBrokenLinksErrorMessage(allBrokenLinks: Record<string, BrokenLink[]>): string | undefined;
17
- export declare function filterExistingFileLinks({ baseUrl, outDir, allCollectedLinks, }: {
18
- baseUrl: string;
19
- outDir: string;
20
- allCollectedLinks: Record<string, string[]>;
21
- }): Promise<Record<string, string[]>>;
22
8
  export declare function handleBrokenLinks({ allCollectedLinks, onBrokenLinks, routes, baseUrl, outDir, }: {
23
- allCollectedLinks: Record<string, string[]>;
9
+ allCollectedLinks: {
10
+ [location: string]: string[];
11
+ };
24
12
  onBrokenLinks: ReportingSeverity;
25
13
  routes: RouteConfig[];
26
14
  baseUrl: string;
27
15
  outDir: string;
28
16
  }): Promise<void>;
29
- export {};
@@ -6,7 +6,7 @@
6
6
  * LICENSE file in the root directory of this source tree.
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.handleBrokenLinks = exports.filterExistingFileLinks = exports.getBrokenLinksErrorMessage = exports.getAllBrokenLinks = void 0;
9
+ exports.handleBrokenLinks = void 0;
10
10
  const tslib_1 = require("tslib");
11
11
  const react_router_config_1 = require("react-router-config");
12
12
  const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
@@ -16,26 +16,24 @@ const utils_2 = require("./utils");
16
16
  const path_1 = tslib_1.__importDefault(require("path"));
17
17
  const combine_promises_1 = tslib_1.__importDefault(require("combine-promises"));
18
18
  const logger_1 = tslib_1.__importDefault(require("@docusaurus/logger"));
19
- function toReactRouterRoutes(routes) {
20
- // @ts-expect-error: types incompatible???
21
- return routes;
22
- }
23
19
  // matchRoutes does not support qs/anchors, so we remove it!
24
20
  function onlyPathname(link) {
25
21
  return link.split('#')[0].split('?')[0];
26
22
  }
27
23
  function getPageBrokenLinks({ pagePath, pageLinks, routes, }) {
28
- // ReactRouter is able to support links like ./../somePath
29
- // but matchRoutes does not do this resolving internally
30
- // we must resolve the links before using matchRoutes
31
- // resolvePathname is used internally by ReactRouter
24
+ // ReactRouter is able to support links like ./../somePath but `matchRoutes`
25
+ // does not do this resolution internally. We must resolve the links before
26
+ // using `matchRoutes`. `resolvePathname` is used internally by React Router
32
27
  function resolveLink(link) {
33
28
  const resolvedLink = (0, utils_1.resolvePathname)(onlyPathname(link), pagePath);
34
29
  return { link, resolvedLink };
35
30
  }
36
31
  function isBrokenLink(link) {
37
32
  const matchedRoutes = [link, decodeURI(link)]
38
- .map((l) => (0, react_router_config_1.matchRoutes)(toReactRouterRoutes(routes), l))
33
+ // @ts-expect-error: React router types RouteConfig with an actual React
34
+ // component, but we load route components with string paths.
35
+ // We don't actually access component here, so it's fine.
36
+ .map((l) => (0, react_router_config_1.matchRoutes)(routes, l))
39
37
  .reduce((prev, cur) => prev.concat(cur));
40
38
  return matchedRoutes.length === 0;
41
39
  }
@@ -44,8 +42,8 @@ function getPageBrokenLinks({ pagePath, pageLinks, routes, }) {
44
42
  /**
45
43
  * The route defs can be recursive, and have a parent match-all route. We don't
46
44
  * want to match broken links like /docs/brokenLink against /docs/*. For this
47
- * reason, we only consider the "final routes", that do not have subroutes.
48
- * We also need to remove the match all 404 route
45
+ * reason, we only consider the "final routes" that do not have subroutes.
46
+ * We also need to remove the match-all 404 route
49
47
  */
50
48
  function filterIntermediateRoutes(routesInput) {
51
49
  const routesWithout404 = routesInput.filter((route) => route.path !== '*');
@@ -57,7 +55,6 @@ function getAllBrokenLinks({ allCollectedLinks, routes, }) {
57
55
  // remove pages without any broken link
58
56
  return lodash_1.default.pickBy(allBrokenLinks, (brokenLinks) => brokenLinks.length > 0);
59
57
  }
60
- exports.getAllBrokenLinks = getAllBrokenLinks;
61
58
  function getBrokenLinksErrorMessage(allBrokenLinks) {
62
59
  if (Object.keys(allBrokenLinks).length === 0) {
63
60
  return undefined;
@@ -93,8 +90,7 @@ function getBrokenLinksErrorMessage(allBrokenLinks) {
93
90
  It looks like some of the broken links we found appear in many pages of your site.
94
91
  Maybe those broken links appear on all pages through your site layout?
95
92
  We recommend that you check your theme configuration for such links (particularly, theme navbar and footer).
96
- Frequent broken links are linking to:${frequentLinks}
97
- `;
93
+ Frequent broken links are linking to:${frequentLinks}`;
98
94
  }
99
95
  return `Docusaurus found broken links!
100
96
 
@@ -107,7 +103,6 @@ ${Object.entries(allBrokenLinks)
107
103
  .join('\n')}
108
104
  `;
109
105
  }
110
- exports.getBrokenLinksErrorMessage = getBrokenLinksErrorMessage;
111
106
  async function isExistingFile(filePath) {
112
107
  try {
113
108
  return (await fs_extra_1.default.stat(filePath)).isFile();
@@ -127,8 +122,7 @@ async function filterExistingFileLinks({ baseUrl, outDir, allCollectedLinks, })
127
122
  // -> /outDir/javadoc/index.html
128
123
  const filePathsToTry = [baseFilePath];
129
124
  if (!path_1.default.extname(baseFilePath)) {
130
- filePathsToTry.push(`${baseFilePath}.html`);
131
- filePathsToTry.push(path_1.default.join(baseFilePath, 'index.html'));
125
+ filePathsToTry.push(`${baseFilePath}.html`, path_1.default.join(baseFilePath, 'index.html'));
132
126
  }
133
127
  for (const file of filePathsToTry) {
134
128
  if (await isExistingFile(file)) {
@@ -139,7 +133,6 @@ async function filterExistingFileLinks({ baseUrl, outDir, allCollectedLinks, })
139
133
  }
140
134
  return (0, combine_promises_1.default)(lodash_1.default.mapValues(allCollectedLinks, async (links) => (await Promise.all(links.map(async (link) => ((await linkFileExists(link)) ? '' : link)))).filter(Boolean)));
141
135
  }
142
- exports.filterExistingFileLinks = filterExistingFileLinks;
143
136
  async function handleBrokenLinks({ allCollectedLinks, onBrokenLinks, routes, baseUrl, outDir, }) {
144
137
  if (onBrokenLinks === 'ignore') {
145
138
  return;