@docusaurus/core 2.0.0-beta.fc64c12e4 → 2.0.0

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 (224) hide show
  1. package/README.md +1 -0
  2. package/bin/beforeCli.mjs +140 -0
  3. package/bin/{docusaurus.js → docusaurus.mjs} +81 -118
  4. package/lib/babel/preset.d.ts +8 -3
  5. package/lib/babel/preset.js +10 -8
  6. package/lib/client/App.d.ts +2 -3
  7. package/lib/client/App.js +31 -28
  8. package/lib/client/BaseUrlIssueBanner/index.d.ts +27 -0
  9. package/lib/client/{baseUrlIssueBanner/BaseUrlIssueBanner.js → BaseUrlIssueBanner/index.js} +25 -14
  10. package/lib/client/{baseUrlIssueBanner → BaseUrlIssueBanner}/styles.module.css +0 -0
  11. package/lib/client/ClientLifecyclesDispatcher.d.ts +16 -0
  12. package/lib/client/ClientLifecyclesDispatcher.js +39 -0
  13. package/lib/client/LinksCollector.d.ts +3 -3
  14. package/lib/client/LinksCollector.js +8 -13
  15. package/lib/client/PendingNavigation.d.ts +17 -3
  16. package/lib/client/PendingNavigation.js +47 -72
  17. package/lib/client/{baseUrlIssueBanner/BaseUrlIssueBanner.d.ts → SiteMetadataDefaults.d.ts} +1 -2
  18. package/lib/client/SiteMetadataDefaults.js +21 -0
  19. package/lib/{choosePort.d.ts → client/browserContext.d.ts} +5 -5
  20. package/lib/client/browserContext.js +22 -0
  21. package/lib/client/clientEntry.js +14 -9
  22. package/lib/client/docusaurus.d.ts +12 -6
  23. package/lib/client/docusaurus.js +30 -43
  24. package/lib/client/docusaurusContext.d.ts +12 -0
  25. package/lib/client/docusaurusContext.js +25 -0
  26. package/lib/client/exports/BrowserOnly.d.ts +3 -5
  27. package/lib/client/exports/BrowserOnly.js +14 -8
  28. package/lib/client/exports/ComponentCreator.d.ts +6 -2
  29. package/lib/client/exports/ComponentCreator.js +75 -42
  30. package/lib/client/exports/ErrorBoundary.d.ts +18 -0
  31. package/lib/client/exports/ErrorBoundary.js +37 -0
  32. package/lib/client/exports/ExecutionEnvironment.js +7 -8
  33. package/lib/client/exports/Head.d.ts +2 -3
  34. package/lib/client/exports/Head.js +3 -4
  35. package/lib/client/exports/Interpolate.d.ts +2 -2
  36. package/lib/client/exports/Interpolate.js +18 -51
  37. package/lib/client/exports/Link.d.ts +4 -10
  38. package/lib/client/exports/Link.js +38 -38
  39. package/lib/client/exports/Translate.d.ts +1 -1
  40. package/lib/client/exports/Translate.js +11 -10
  41. package/lib/client/exports/constants.js +1 -11
  42. package/lib/client/exports/isInternalUrl.js +1 -1
  43. package/lib/client/exports/renderRoutes.d.ts +1 -2
  44. package/lib/client/exports/renderRoutes.js +1 -2
  45. package/lib/client/exports/router.d.ts +1 -1
  46. package/lib/client/exports/router.js +1 -1
  47. package/lib/client/exports/useBaseUrl.js +11 -14
  48. package/lib/client/exports/useDocusaurusContext.d.ts +2 -3
  49. package/lib/client/exports/useDocusaurusContext.js +3 -9
  50. package/lib/client/exports/useGlobalData.d.ts +4 -3
  51. package/lib/client/exports/useGlobalData.js +6 -13
  52. package/lib/{server/versions/__tests/index.test.d.ts → client/exports/useIsBrowser.d.ts} +1 -1
  53. package/lib/client/exports/useIsBrowser.js +11 -0
  54. package/lib/client/exports/useRouteContext.d.ts +8 -0
  55. package/lib/client/exports/useRouteContext.js +15 -0
  56. package/lib/client/flat.d.ts +12 -2
  57. package/lib/client/flat.js +19 -15
  58. package/lib/client/normalizeLocation.d.ts +2 -5
  59. package/lib/client/normalizeLocation.js +14 -10
  60. package/lib/client/prefetch.d.ts +1 -2
  61. package/lib/client/prefetch.js +12 -32
  62. package/lib/client/preload.d.ts +3 -4
  63. package/lib/client/preload.js +5 -12
  64. package/lib/client/routeContext.d.ts +13 -0
  65. package/lib/client/routeContext.js +31 -0
  66. package/lib/client/serverEntry.d.ts +10 -0
  67. package/lib/client/serverEntry.js +108 -146
  68. package/lib/client/theme-fallback/Error/index.d.ts +10 -0
  69. package/lib/client/theme-fallback/Error/index.js +45 -0
  70. package/lib/client/theme-fallback/Layout/index.d.ts +10 -0
  71. package/lib/client/theme-fallback/Layout/index.js +2 -26
  72. package/lib/client/theme-fallback/Loading/index.d.ts +9 -0
  73. package/lib/client/theme-fallback/Loading/index.js +50 -116
  74. package/lib/{server/html-tags/htmlTags.d.ts → client/theme-fallback/NotFound/index.d.ts} +2 -1
  75. package/lib/client/theme-fallback/NotFound/index.js +19 -18
  76. package/lib/client/theme-fallback/Root/index.d.ts +10 -0
  77. package/lib/client/theme-fallback/Root/index.js +2 -6
  78. package/lib/client/{exports/context.js → theme-fallback/SiteMetadata/index.d.ts} +2 -2
  79. package/lib/client/theme-fallback/SiteMetadata/index.js +10 -0
  80. package/lib/commands/build.d.ts +6 -2
  81. package/lib/commands/build.js +81 -64
  82. package/lib/commands/clear.d.ts +7 -1
  83. package/lib/commands/clear.js +34 -21
  84. package/lib/commands/deploy.d.ts +5 -2
  85. package/lib/commands/deploy.js +94 -81
  86. package/lib/commands/external.d.ts +2 -2
  87. package/lib/commands/external.js +9 -11
  88. package/lib/commands/serve.d.ts +8 -2
  89. package/lib/commands/serve.js +29 -28
  90. package/lib/commands/start.d.ts +9 -2
  91. package/lib/commands/start.js +107 -102
  92. package/lib/commands/swizzle/actions.d.ts +23 -0
  93. package/lib/commands/swizzle/actions.js +106 -0
  94. package/lib/commands/swizzle/common.d.ts +33 -0
  95. package/lib/commands/swizzle/common.js +56 -0
  96. package/lib/commands/swizzle/components.d.ts +29 -0
  97. package/lib/commands/swizzle/components.js +200 -0
  98. package/lib/commands/swizzle/config.d.ts +10 -0
  99. package/lib/commands/swizzle/config.js +84 -0
  100. package/lib/{server/client-modules/index.d.ts → commands/swizzle/context.d.ts} +2 -2
  101. package/lib/commands/swizzle/context.js +24 -0
  102. package/lib/commands/swizzle/index.d.ts +8 -0
  103. package/lib/commands/swizzle/index.js +119 -0
  104. package/lib/commands/swizzle/prompts.d.ts +12 -0
  105. package/lib/commands/swizzle/prompts.js +110 -0
  106. package/lib/{client/exports/context.d.ts → commands/swizzle/tables.d.ts} +3 -4
  107. package/lib/commands/swizzle/tables.js +113 -0
  108. package/lib/commands/swizzle/themes.d.ts +20 -0
  109. package/lib/commands/swizzle/themes.js +106 -0
  110. package/lib/commands/writeHeadingIds.d.ts +2 -6
  111. package/lib/commands/writeHeadingIds.js +22 -81
  112. package/lib/commands/writeTranslations.d.ts +4 -5
  113. package/lib/commands/writeTranslations.js +46 -25
  114. package/lib/index.d.ts +9 -9
  115. package/lib/index.js +14 -14
  116. package/lib/server/brokenLinks.d.ts +4 -17
  117. package/lib/server/brokenLinks.js +67 -56
  118. package/lib/server/clientModules.d.ts +12 -0
  119. package/lib/server/clientModules.js +20 -0
  120. package/lib/server/config.d.ts +5 -2
  121. package/lib/server/config.js +29 -6
  122. package/lib/server/configValidation.d.ts +4 -4
  123. package/lib/server/configValidation.js +86 -41
  124. package/lib/server/getHostPort.d.ts +14 -0
  125. package/lib/server/getHostPort.js +79 -0
  126. package/lib/server/htmlTags.d.ts +12 -0
  127. package/lib/server/htmlTags.js +62 -0
  128. package/lib/server/i18n.d.ts +3 -13
  129. package/lib/server/i18n.js +21 -55
  130. package/lib/server/index.d.ts +28 -13
  131. package/lib/server/index.js +83 -165
  132. package/lib/server/plugins/configs.d.ts +51 -0
  133. package/lib/server/plugins/configs.js +101 -0
  134. package/lib/server/plugins/index.d.ts +9 -8
  135. package/lib/server/plugins/index.js +73 -137
  136. package/lib/server/plugins/init.d.ts +6 -5
  137. package/lib/server/plugins/init.js +44 -109
  138. package/lib/server/plugins/moduleShorthand.d.ts +9 -0
  139. package/lib/server/plugins/moduleShorthand.js +46 -0
  140. package/lib/server/plugins/pluginIds.d.ts +5 -1
  141. package/lib/server/plugins/pluginIds.js +12 -7
  142. package/lib/server/plugins/presets.d.ts +12 -0
  143. package/lib/server/plugins/presets.js +49 -0
  144. package/lib/server/plugins/routeConfig.d.ts +11 -0
  145. package/lib/server/plugins/routeConfig.js +54 -0
  146. package/lib/server/plugins/synthetic.d.ts +20 -0
  147. package/lib/server/plugins/synthetic.js +111 -0
  148. package/lib/server/routes.d.ts +39 -7
  149. package/lib/server/routes.js +166 -99
  150. package/lib/server/siteMetadata.d.ts +12 -0
  151. package/lib/server/siteMetadata.js +81 -0
  152. package/lib/server/translations/translations.d.ts +14 -19
  153. package/lib/server/translations/translations.js +40 -72
  154. package/lib/server/translations/translationsExtractor.d.ts +10 -4
  155. package/lib/server/translations/translationsExtractor.js +158 -122
  156. package/lib/server/utils.d.ts +7 -1
  157. package/lib/server/utils.js +7 -8
  158. package/lib/webpack/aliases/index.d.ts +34 -0
  159. package/lib/webpack/aliases/index.js +106 -0
  160. package/lib/webpack/base.d.ts +3 -4
  161. package/lib/webpack/base.js +45 -57
  162. package/lib/webpack/client.d.ts +3 -3
  163. package/lib/webpack/client.js +12 -19
  164. package/lib/webpack/plugins/ChunkAssetPlugin.d.ts +13 -3
  165. package/lib/webpack/plugins/ChunkAssetPlugin.js +24 -17
  166. package/lib/webpack/plugins/CleanWebpackPlugin.d.ts +6 -25
  167. package/lib/webpack/plugins/CleanWebpackPlugin.js +33 -17
  168. package/lib/webpack/plugins/LogPlugin.d.ts +1 -1
  169. package/lib/webpack/plugins/LogPlugin.js +4 -5
  170. package/lib/webpack/plugins/WaitPlugin.d.ts +3 -3
  171. package/lib/webpack/plugins/WaitPlugin.js +30 -29
  172. package/lib/webpack/server.d.ts +5 -5
  173. package/lib/webpack/server.js +21 -12
  174. package/lib/{client → webpack}/templates/index.html.template.ejs +0 -0
  175. package/lib/webpack/templates/ssr.html.template.d.ts +8 -0
  176. package/lib/{client → webpack}/templates/ssr.html.template.js +3 -2
  177. package/lib/webpack/utils.d.ts +15 -31
  178. package/lib/webpack/utils.js +61 -182
  179. package/package.json +81 -77
  180. package/bin/beforeCli.js +0 -103
  181. package/lib/.tsbuildinfo +0 -1
  182. package/lib/choosePort.js +0 -105
  183. package/lib/client/.eslintrc.js +0 -29
  184. package/lib/client/.tsbuildinfo +0 -1
  185. package/lib/client/client-lifecycles-dispatcher.d.ts +0 -12
  186. package/lib/client/client-lifecycles-dispatcher.js +0 -27
  187. package/lib/client/nprogress.css +0 -36
  188. package/lib/commands/buildRemoteBranchUrl.d.ts +0 -7
  189. package/lib/commands/buildRemoteBranchUrl.js +0 -27
  190. package/lib/commands/commandUtils.d.ts +0 -3
  191. package/lib/commands/commandUtils.js +0 -21
  192. package/lib/commands/swizzle.d.ts +0 -9
  193. package/lib/commands/swizzle.js +0 -245
  194. package/lib/constants.d.ts +0 -18
  195. package/lib/constants.js +0 -23
  196. package/lib/server/client-modules/index.js +0 -14
  197. package/lib/server/duplicateRoutes.d.ts +0 -10
  198. package/lib/server/duplicateRoutes.js +0 -38
  199. package/lib/server/html-tags/htmlTags.js +0 -40
  200. package/lib/server/html-tags/index.d.ts +0 -9
  201. package/lib/server/html-tags/index.js +0 -43
  202. package/lib/server/loadSetup.d.ts +0 -9
  203. package/lib/server/loadSetup.js +0 -25
  204. package/lib/server/plugins/applyRouteTrailingSlash.d.ts +0 -9
  205. package/lib/server/plugins/applyRouteTrailingSlash.js +0 -19
  206. package/lib/server/presets/index.d.ts +0 -11
  207. package/lib/server/presets/index.js +0 -48
  208. package/lib/server/themes/alias.d.ts +0 -8
  209. package/lib/server/themes/alias.js +0 -39
  210. package/lib/server/themes/index.d.ts +0 -12
  211. package/lib/server/themes/index.js +0 -47
  212. package/lib/server/versions/__fixtures__/dummy-plugin.js +0 -0
  213. package/lib/server/versions/__fixtures__/package.json +0 -3
  214. package/lib/server/versions/__tests/index.test.js +0 -25
  215. package/lib/server/versions/index.d.ts +0 -10
  216. package/lib/server/versions/index.js +0 -50
  217. package/lib/webpack/react-dev-utils-webpack5/README.md +0 -11
  218. package/lib/webpack/react-dev-utils-webpack5/evalSourceMapMiddleware.js +0 -57
  219. package/lib/webpack/react-dev-utils-webpack5/formatWebpackMessages.js +0 -138
  220. package/lib/webpack/react-dev-utils-webpack5/webpackHotDevClient.js +0 -285
  221. package/lib/webpack/sharedModuleAliases.d.ts +0 -10
  222. package/lib/webpack/sharedModuleAliases.js +0 -18
  223. package/tsconfig.client.json +0 -13
  224. package/tsconfig.json +0 -13
@@ -6,57 +6,54 @@
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
- const react_router_config_1 = require("react-router-config");
12
- const resolve_pathname_1 = tslib_1.__importDefault(require("resolve-pathname"));
13
11
  const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
14
- const lodash_1 = require("lodash");
12
+ const path_1 = tslib_1.__importDefault(require("path"));
13
+ const lodash_1 = tslib_1.__importDefault(require("lodash"));
14
+ const logger_1 = tslib_1.__importDefault(require("@docusaurus/logger"));
15
+ const combine_promises_1 = tslib_1.__importDefault(require("combine-promises"));
16
+ const react_router_config_1 = require("react-router-config");
15
17
  const utils_1 = require("@docusaurus/utils");
16
18
  const utils_2 = require("./utils");
17
- const path_1 = tslib_1.__importDefault(require("path"));
18
- function toReactRouterRoutes(routes) {
19
- // @ts-expect-error: types incompatible???
20
- return routes;
21
- }
22
19
  // matchRoutes does not support qs/anchors, so we remove it!
23
20
  function onlyPathname(link) {
24
21
  return link.split('#')[0].split('?')[0];
25
22
  }
26
23
  function getPageBrokenLinks({ pagePath, pageLinks, routes, }) {
27
- // ReactRouter is able to support links like ./../somePath
28
- // but matchRoutes does not do this resolving internally
29
- // we must resolve the links before using matchRoutes
30
- // 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
31
27
  function resolveLink(link) {
32
- const resolvedLink = resolve_pathname_1.default(onlyPathname(link), pagePath);
28
+ const resolvedLink = (0, utils_1.resolvePathname)(onlyPathname(link), pagePath);
33
29
  return { link, resolvedLink };
34
30
  }
35
31
  function isBrokenLink(link) {
36
32
  const matchedRoutes = [link, decodeURI(link)]
37
- .map((l) => react_router_config_1.matchRoutes(toReactRouterRoutes(routes), l))
38
- .reduce((prev, cur) => prev.concat(cur));
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))
37
+ .flat();
39
38
  return matchedRoutes.length === 0;
40
39
  }
41
40
  return pageLinks.map(resolveLink).filter((l) => isBrokenLink(l.resolvedLink));
42
41
  }
43
- // The route defs can be recursive, and have a parent match-all route
44
- // We don't want to match broken links like /docs/brokenLink against /docs/*
45
- // For this reason, we only consider the "final routes", that do not have subroutes
46
- // We also need to remove the match all 404 route
42
+ /**
43
+ * The route defs can be recursive, and have a parent match-all route. We don't
44
+ * want to match broken links like /docs/brokenLink against /docs/*. For this
45
+ * reason, we only consider the "final routes" that do not have subroutes.
46
+ * We also need to remove the match-all 404 route
47
+ */
47
48
  function filterIntermediateRoutes(routesInput) {
48
49
  const routesWithout404 = routesInput.filter((route) => route.path !== '*');
49
- return utils_2.getAllFinalRoutes(routesWithout404);
50
+ return (0, utils_2.getAllFinalRoutes)(routesWithout404);
50
51
  }
51
52
  function getAllBrokenLinks({ allCollectedLinks, routes, }) {
52
53
  const filteredRoutes = filterIntermediateRoutes(routes);
53
- const allBrokenLinks = lodash_1.mapValues(allCollectedLinks, (pageLinks, pagePath) => {
54
- return getPageBrokenLinks({ pageLinks, pagePath, routes: filteredRoutes });
55
- });
56
- // remove pages without any broken link
57
- return lodash_1.pickBy(allBrokenLinks, (brokenLinks) => brokenLinks.length > 0);
54
+ const allBrokenLinks = lodash_1.default.mapValues(allCollectedLinks, (pageLinks, pagePath) => getPageBrokenLinks({ pageLinks, pagePath, routes: filteredRoutes }));
55
+ return lodash_1.default.pickBy(allBrokenLinks, (brokenLinks) => brokenLinks.length > 0);
58
56
  }
59
- exports.getAllBrokenLinks = getAllBrokenLinks;
60
57
  function getBrokenLinksErrorMessage(allBrokenLinks) {
61
58
  if (Object.keys(allBrokenLinks).length === 0) {
62
59
  return undefined;
@@ -66,16 +63,20 @@ function getBrokenLinksErrorMessage(allBrokenLinks) {
66
63
  return `${brokenLink.link}${showResolvedLink ? ` (resolved as: ${brokenLink.resolvedLink})` : ''}`;
67
64
  }
68
65
  function pageBrokenLinksMessage(pagePath, brokenLinks) {
69
- return `\n- On source page path = ${pagePath}:\n -> linking to ${brokenLinks
66
+ return `
67
+ - On source page path = ${pagePath}:
68
+ -> linking to ${brokenLinks
70
69
  .map(brokenLinkMessage)
71
70
  .join('\n -> linking to ')}`;
72
71
  }
73
- // If there's a broken link appearing very often, it is probably a broken link on the layout!
74
- // Add an additional message in such case to help user figure this out.
75
- // see https://github.com/facebook/docusaurus/issues/3567#issuecomment-706973805
72
+ /**
73
+ * If there's a broken link appearing very often, it is probably a broken link
74
+ * on the layout. Add an additional message in such case to help user figure
75
+ * this out. See https://github.com/facebook/docusaurus/issues/3567#issuecomment-706973805
76
+ */
76
77
  function getLayoutBrokenLinksHelpMessage() {
77
- const flatList = lodash_1.flatten(Object.entries(allBrokenLinks).map(([pagePage, brokenLinks]) => brokenLinks.map((brokenLink) => ({ pagePage, brokenLink }))));
78
- const countedBrokenLinks = lodash_1.countBy(flatList, (item) => item.brokenLink.link);
78
+ const flatList = Object.entries(allBrokenLinks).flatMap(([pagePage, brokenLinks]) => brokenLinks.map((brokenLink) => ({ pagePage, brokenLink })));
79
+ const countedBrokenLinks = lodash_1.default.countBy(flatList, (item) => item.brokenLink.link);
79
80
  const FrequencyThreshold = 5; // Is this a good value?
80
81
  const frequentLinks = Object.entries(countedBrokenLinks)
81
82
  .filter(([, count]) => count >= FrequencyThreshold)
@@ -83,51 +84,61 @@ function getBrokenLinksErrorMessage(allBrokenLinks) {
83
84
  if (frequentLinks.length === 0) {
84
85
  return '';
85
86
  }
86
- return `\n\nIt looks like some of the broken links we found appear in many pages of your site.\nMaybe those broken links appear on all pages through your site layout?\nWe recommend that you check your theme configuration for such links (particularly, theme navbar and footer).\nFrequent broken links are linking to:\n- ${frequentLinks.join(`\n- `)}\n`;
87
+ return logger_1.default.interpolate `
88
+
89
+ It looks like some of the broken links we found appear in many pages of your site.
90
+ Maybe those broken links appear on all pages through your site layout?
91
+ We recommend that you check your theme configuration for such links (particularly, theme navbar and footer).
92
+ Frequent broken links are linking to:${frequentLinks}`;
87
93
  }
88
- return (`Docusaurus found broken links!\n\nPlease check the pages of your site in the list below, and make sure you don't reference any path that does not exist.\nNote: it's possible to ignore broken links with the 'onBrokenLinks' Docusaurus configuration, and let the build pass.${getLayoutBrokenLinksHelpMessage()}` +
89
- `\n\nExhaustive list of all broken links found:\n${Object.entries(allBrokenLinks)
90
- .map(([pagePath, brokenLinks]) => pageBrokenLinksMessage(pagePath, brokenLinks))
91
- .join('\n')}
92
- `);
94
+ return `Docusaurus found broken links!
95
+
96
+ Please check the pages of your site in the list below, and make sure you don't reference any path that does not exist.
97
+ Note: it's possible to ignore broken links with the 'onBrokenLinks' Docusaurus configuration, and let the build pass.${getLayoutBrokenLinksHelpMessage()}
98
+
99
+ Exhaustive list of all broken links found:
100
+ ${Object.entries(allBrokenLinks)
101
+ .map(([pagePath, brokenLinks]) => pageBrokenLinksMessage(pagePath, brokenLinks))
102
+ .join('\n')}
103
+ `;
93
104
  }
94
- exports.getBrokenLinksErrorMessage = getBrokenLinksErrorMessage;
95
- function isExistingFile(filePath) {
105
+ async function isExistingFile(filePath) {
96
106
  try {
97
- return fs_extra_1.default.statSync(filePath).isFile();
107
+ return (await fs_extra_1.default.stat(filePath)).isFile();
98
108
  }
99
- catch (e) {
109
+ catch {
100
110
  return false;
101
111
  }
102
112
  }
103
113
  // If a file actually exist on the file system, we know the link is valid
104
114
  // even if docusaurus does not know about this file, so we don't report it
105
115
  async function filterExistingFileLinks({ baseUrl, outDir, allCollectedLinks, }) {
106
- // not easy to make this async :'(
107
- function linkFileExists(link) {
116
+ async function linkFileExists(link) {
108
117
  // /baseUrl/javadoc/ -> /outDir/javadoc
109
- const baseFilePath = utils_1.removeSuffix(`${outDir}/${utils_1.removePrefix(link, baseUrl)}`, '/');
118
+ const baseFilePath = onlyPathname((0, utils_1.removeSuffix)(`${outDir}/${(0, utils_1.removePrefix)(link, baseUrl)}`, '/'));
110
119
  // -> /outDir/javadoc
111
120
  // -> /outDir/javadoc.html
112
121
  // -> /outDir/javadoc/index.html
113
122
  const filePathsToTry = [baseFilePath];
114
123
  if (!path_1.default.extname(baseFilePath)) {
115
- filePathsToTry.push(`${baseFilePath}.html`);
116
- filePathsToTry.push(path_1.default.join(baseFilePath, 'index.html'));
124
+ filePathsToTry.push(`${baseFilePath}.html`, path_1.default.join(baseFilePath, 'index.html'));
125
+ }
126
+ for (const file of filePathsToTry) {
127
+ if (await isExistingFile(file)) {
128
+ return true;
129
+ }
117
130
  }
118
- return filePathsToTry.some(isExistingFile);
131
+ return false;
119
132
  }
120
- return lodash_1.mapValues(allCollectedLinks, (links) => {
121
- return links.filter((link) => !linkFileExists(link));
122
- });
133
+ 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)));
123
134
  }
124
- exports.filterExistingFileLinks = filterExistingFileLinks;
125
135
  async function handleBrokenLinks({ allCollectedLinks, onBrokenLinks, routes, baseUrl, outDir, }) {
126
136
  if (onBrokenLinks === 'ignore') {
127
137
  return;
128
138
  }
129
- // If we link to a file like /myFile.zip, and the file actually exist for the file system
130
- // it is not a broken link, it may simply be a link to an existing static file...
139
+ // If we link to a file like /myFile.zip, and the file actually exist for the
140
+ // file system. It is not a broken link, it may simply be a link to an
141
+ // existing static file...
131
142
  const allCollectedLinksFiltered = await filterExistingFileLinks({
132
143
  allCollectedLinks,
133
144
  baseUrl,
@@ -139,7 +150,7 @@ async function handleBrokenLinks({ allCollectedLinks, onBrokenLinks, routes, bas
139
150
  });
140
151
  const errorMessage = getBrokenLinksErrorMessage(allBrokenLinks);
141
152
  if (errorMessage) {
142
- utils_1.reportMessage(errorMessage, onBrokenLinks);
153
+ logger_1.default.report(onBrokenLinks)(errorMessage);
143
154
  }
144
155
  }
145
156
  exports.handleBrokenLinks = handleBrokenLinks;
@@ -0,0 +1,12 @@
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 { LoadedPlugin } from '@docusaurus/types';
8
+ /**
9
+ * Runs the `getClientModules` lifecycle. The returned file paths are all
10
+ * absolute.
11
+ */
12
+ export declare function loadClientModules(plugins: LoadedPlugin[]): string[];
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) Facebook, Inc. and its affiliates.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.loadClientModules = void 0;
10
+ const tslib_1 = require("tslib");
11
+ const path_1 = tslib_1.__importDefault(require("path"));
12
+ /**
13
+ * Runs the `getClientModules` lifecycle. The returned file paths are all
14
+ * absolute.
15
+ */
16
+ function loadClientModules(plugins) {
17
+ return plugins.flatMap((plugin) => plugin.getClientModules?.().map((p) => path_1.default.resolve(plugin.path, p)) ??
18
+ []);
19
+ }
20
+ exports.loadClientModules = loadClientModules;
@@ -4,5 +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
- import { DocusaurusConfig } from '@docusaurus/types';
8
- export default function loadConfig(configPath: string): DocusaurusConfig;
7
+ import type { LoadContext } from '@docusaurus/types';
8
+ export declare function loadSiteConfig({ siteDir, customConfigFilePath, }: {
9
+ siteDir: string;
10
+ customConfigFilePath?: string;
11
+ }): Promise<Pick<LoadContext, 'siteConfig' | 'siteConfigPath'>>;
@@ -6,15 +6,38 @@
6
6
  * LICENSE file in the root directory of this source tree.
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.loadSiteConfig = void 0;
9
10
  const tslib_1 = require("tslib");
11
+ const path_1 = tslib_1.__importDefault(require("path"));
10
12
  const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
11
13
  const import_fresh_1 = tslib_1.__importDefault(require("import-fresh"));
14
+ const logger_1 = tslib_1.__importDefault(require("@docusaurus/logger"));
15
+ const utils_1 = require("@docusaurus/utils");
12
16
  const configValidation_1 = require("./configValidation");
13
- function loadConfig(configPath) {
14
- if (!fs_extra_1.default.existsSync(configPath)) {
15
- throw new Error(`Config file at "${configPath}" not found.`);
17
+ async function findConfig(siteDir) {
18
+ // We could support .mjs, .ts, etc. in the future
19
+ const candidates = ['.js', '.cjs'].map((ext) => utils_1.DEFAULT_CONFIG_FILE_NAME + ext);
20
+ const configPath = await (0, utils_1.findAsyncSequential)(candidates.map((file) => path_1.default.join(siteDir, file)), fs_extra_1.default.pathExists);
21
+ if (!configPath) {
22
+ logger_1.default.error('No config file found.');
23
+ logger_1.default.info `Expected one of:${candidates}
24
+ You can provide a custom config path with the code=${'--config'} option.`;
25
+ throw new Error();
16
26
  }
17
- const loadedConfig = import_fresh_1.default(configPath);
18
- return configValidation_1.validateConfig(loadedConfig);
27
+ return configPath;
19
28
  }
20
- exports.default = loadConfig;
29
+ async function loadSiteConfig({ siteDir, customConfigFilePath, }) {
30
+ const siteConfigPath = customConfigFilePath
31
+ ? path_1.default.resolve(siteDir, customConfigFilePath)
32
+ : await findConfig(siteDir);
33
+ if (!(await fs_extra_1.default.pathExists(siteConfigPath))) {
34
+ throw new Error(`Config file at "${siteConfigPath}" not found.`);
35
+ }
36
+ const importedConfig = (0, import_fresh_1.default)(siteConfigPath);
37
+ const loadedConfig = typeof importedConfig === 'function'
38
+ ? await importedConfig()
39
+ : await importedConfig;
40
+ const siteConfig = (0, configValidation_1.validateConfig)(loadedConfig, path_1.default.relative(siteDir, siteConfigPath));
41
+ return { siteConfig, siteConfigPath };
42
+ }
43
+ exports.loadSiteConfig = loadSiteConfig;
@@ -4,9 +4,9 @@
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 { DocusaurusConfig, I18nConfig } from '@docusaurus/types';
8
7
  import { Joi } from '@docusaurus/utils-validation';
8
+ import type { DocusaurusConfig, I18nConfig } from '@docusaurus/types';
9
9
  export declare const DEFAULT_I18N_CONFIG: I18nConfig;
10
- export declare const DEFAULT_CONFIG: Pick<DocusaurusConfig, 'i18n' | 'onBrokenLinks' | 'onBrokenMarkdownLinks' | 'onDuplicateRoutes' | 'plugins' | 'themes' | 'presets' | 'customFields' | 'themeConfig' | 'titleDelimiter' | 'noIndex' | 'baseUrlIssueBanner'>;
11
- export declare const ConfigSchema: Joi.ObjectSchema<any>;
12
- export declare function validateConfig(config: Partial<DocusaurusConfig>): DocusaurusConfig;
10
+ export declare const DEFAULT_CONFIG: Pick<DocusaurusConfig, 'i18n' | 'onBrokenLinks' | 'onBrokenMarkdownLinks' | 'onDuplicateRoutes' | 'plugins' | 'themes' | 'presets' | 'stylesheets' | 'scripts' | 'clientModules' | 'customFields' | 'themeConfig' | 'titleDelimiter' | 'noIndex' | 'tagline' | 'baseUrlIssueBanner' | 'staticDirectories'>;
11
+ export declare const ConfigSchema: Joi.ObjectSchema<DocusaurusConfig>;
12
+ export declare function validateConfig(config: unknown, siteConfigPath: string): DocusaurusConfig;
@@ -7,11 +7,12 @@
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.validateConfig = exports.ConfigSchema = exports.DEFAULT_CONFIG = exports.DEFAULT_I18N_CONFIG = void 0;
10
- const constants_1 = require("../constants");
10
+ const utils_1 = require("@docusaurus/utils");
11
11
  const utils_validation_1 = require("@docusaurus/utils-validation");
12
12
  const DEFAULT_I18N_LOCALE = 'en';
13
13
  exports.DEFAULT_I18N_CONFIG = {
14
14
  defaultLocale: DEFAULT_I18N_LOCALE,
15
+ path: utils_1.DEFAULT_I18N_DIR_NAME,
15
16
  locales: [DEFAULT_I18N_LOCALE],
16
17
  localeConfigs: {},
17
18
  };
@@ -23,23 +24,39 @@ exports.DEFAULT_CONFIG = {
23
24
  plugins: [],
24
25
  themes: [],
25
26
  presets: [],
27
+ stylesheets: [],
28
+ scripts: [],
29
+ clientModules: [],
26
30
  customFields: {},
27
31
  themeConfig: {},
28
32
  titleDelimiter: '|',
29
33
  noIndex: false,
34
+ tagline: '',
30
35
  baseUrlIssueBanner: true,
36
+ staticDirectories: [utils_1.DEFAULT_STATIC_DIR_NAME],
31
37
  };
32
- const PluginSchema = utils_validation_1.Joi.alternatives()
33
- .try(utils_validation_1.Joi.function(), utils_validation_1.Joi.array().ordered(utils_validation_1.Joi.function().required(), utils_validation_1.Joi.object().required()), utils_validation_1.Joi.string(), utils_validation_1.Joi.array()
34
- .ordered(utils_validation_1.Joi.string().required(), utils_validation_1.Joi.object().required())
35
- .length(2), utils_validation_1.Joi.bool().equal(false))
36
- // TODO isn't there a simpler way to customize the default Joi error message???
37
- // Not sure why Joi makes it complicated to add a custom error message...
38
- // See https://stackoverflow.com/a/54657686/82609
39
- .error((errors) => {
40
- errors.forEach((error) => {
41
- error.message = ` => Bad Docusaurus plugin value as path [${error.path}].
42
- Example valid plugin config:
38
+ function createPluginSchema(theme) {
39
+ return (utils_validation_1.Joi.alternatives()
40
+ .try(utils_validation_1.Joi.function(), utils_validation_1.Joi.array()
41
+ .ordered(utils_validation_1.Joi.function().required(), utils_validation_1.Joi.object().required())
42
+ .length(2), utils_validation_1.Joi.string(), utils_validation_1.Joi.array()
43
+ .ordered(utils_validation_1.Joi.string().required(), utils_validation_1.Joi.object().required())
44
+ .length(2), utils_validation_1.Joi.any().valid(false, null))
45
+ // @ts-expect-error: bad lib def, doesn't recognize an array of reports
46
+ .error((errors) => {
47
+ errors.forEach((error) => {
48
+ const validConfigExample = theme
49
+ ? `Example valid theme config:
50
+ {
51
+ themes: [
52
+ ["@docusaurus/theme-classic",options],
53
+ "./myTheme",
54
+ ["./myTheme",{someOption: 42}],
55
+ function myTheme() { },
56
+ [function myTheme() { },options]
57
+ ],
58
+ };`
59
+ : `Example valid plugin config:
43
60
  {
44
61
  plugins: [
45
62
  ["@docusaurus/plugin-content-docs",options],
@@ -48,19 +65,35 @@ Example valid plugin config:
48
65
  function myPlugin() { },
49
66
  [function myPlugin() { },options]
50
67
  ],
51
- };
68
+ };`;
69
+ error.message = ` => Bad Docusaurus ${theme ? 'theme' : 'plugin'} value ${error.path.reduce((acc, cur) => typeof cur === 'string' ? `${acc}.${cur}` : `${acc}[${cur}]`)}.
70
+ ${validConfigExample}
52
71
  `;
53
- });
54
- return errors;
72
+ });
73
+ return errors;
74
+ }));
75
+ }
76
+ const PluginSchema = createPluginSchema(false);
77
+ const ThemeSchema = createPluginSchema(true);
78
+ const PresetSchema = utils_validation_1.Joi.alternatives()
79
+ .try(utils_validation_1.Joi.string(), utils_validation_1.Joi.array()
80
+ .items(utils_validation_1.Joi.string().required(), utils_validation_1.Joi.object().required())
81
+ .length(2), utils_validation_1.Joi.any().valid(false, null))
82
+ .messages({
83
+ 'alternatives.types': `{#label} does not look like a valid preset config. A preset config entry should be one of:
84
+ - A tuple of [presetName, options], like \`["classic", \\{ blog: false \\}]\`, or
85
+ - A simple string, like \`"classic"\``,
55
86
  });
56
- const ThemeSchema = utils_validation_1.Joi.alternatives().try(utils_validation_1.Joi.string(), utils_validation_1.Joi.array().items(utils_validation_1.Joi.string().required(), utils_validation_1.Joi.object().required()).length(2));
57
- const PresetSchema = utils_validation_1.Joi.alternatives().try(utils_validation_1.Joi.string(), utils_validation_1.Joi.array().items(utils_validation_1.Joi.string().required(), utils_validation_1.Joi.object().required()).length(2));
58
87
  const LocaleConfigSchema = utils_validation_1.Joi.object({
59
88
  label: utils_validation_1.Joi.string(),
89
+ htmlLang: utils_validation_1.Joi.string(),
60
90
  direction: utils_validation_1.Joi.string().equal('ltr', 'rtl').default('ltr'),
91
+ calendar: utils_validation_1.Joi.string(),
92
+ path: utils_validation_1.Joi.string(),
61
93
  });
62
94
  const I18N_CONFIG_SCHEMA = utils_validation_1.Joi.object({
63
95
  defaultLocale: utils_validation_1.Joi.string().required(),
96
+ path: utils_validation_1.Joi.string().default(exports.DEFAULT_I18N_CONFIG.path),
64
97
  locales: utils_validation_1.Joi.array().items().min(1).items(utils_validation_1.Joi.string().required()).required(),
65
98
  localeConfigs: utils_validation_1.Joi.object()
66
99
  .pattern(/.*/, LocaleConfigSchema)
@@ -68,23 +101,23 @@ const I18N_CONFIG_SCHEMA = utils_validation_1.Joi.object({
68
101
  })
69
102
  .optional()
70
103
  .default(exports.DEFAULT_I18N_CONFIG);
71
- const SiteUrlSchema = utils_validation_1.URISchema.required().custom(function (value, helpers) {
104
+ const SiteUrlSchema = utils_validation_1.URISchema.required().custom((value, helpers) => {
72
105
  try {
73
- const { pathname } = new URL(value);
106
+ const { pathname } = new URL(String(value));
74
107
  if (pathname !== '/') {
75
108
  helpers.warn('docusaurus.configValidationWarning', {
76
109
  warningMessage: `the url is not supposed to contain a sub-path like '${pathname}', please use the baseUrl field for sub-paths`,
77
110
  });
78
111
  }
79
112
  }
80
- catch (e) { }
113
+ catch { }
81
114
  return value;
82
115
  }, 'siteUrlCustomValidation');
83
116
  // TODO move to @docusaurus/utils-validation
84
117
  exports.ConfigSchema = utils_validation_1.Joi.object({
85
118
  baseUrl: utils_validation_1.Joi.string()
86
119
  .required()
87
- .regex(new RegExp('/$', 'm'))
120
+ .regex(/\/$/m)
88
121
  .message('{{#label}} must be a string with a trailing slash.'),
89
122
  baseUrlIssueBanner: utils_validation_1.Joi.boolean().default(exports.DEFAULT_CONFIG.baseUrlIssueBanner),
90
123
  favicon: utils_validation_1.Joi.string().optional(),
@@ -93,38 +126,55 @@ exports.ConfigSchema = utils_validation_1.Joi.object({
93
126
  trailingSlash: utils_validation_1.Joi.boolean(),
94
127
  i18n: I18N_CONFIG_SCHEMA,
95
128
  onBrokenLinks: utils_validation_1.Joi.string()
96
- .equal('ignore', 'log', 'warn', 'error', 'throw')
129
+ .equal('ignore', 'log', 'warn', 'throw')
97
130
  .default(exports.DEFAULT_CONFIG.onBrokenLinks),
98
131
  onBrokenMarkdownLinks: utils_validation_1.Joi.string()
99
- .equal('ignore', 'log', 'warn', 'error', 'throw')
132
+ .equal('ignore', 'log', 'warn', 'throw')
100
133
  .default(exports.DEFAULT_CONFIG.onBrokenMarkdownLinks),
101
134
  onDuplicateRoutes: utils_validation_1.Joi.string()
102
- .equal('ignore', 'log', 'warn', 'error', 'throw')
135
+ .equal('ignore', 'log', 'warn', 'throw')
103
136
  .default(exports.DEFAULT_CONFIG.onDuplicateRoutes),
104
137
  organizationName: utils_validation_1.Joi.string().allow(''),
138
+ staticDirectories: utils_validation_1.Joi.array()
139
+ .items(utils_validation_1.Joi.string())
140
+ .default(exports.DEFAULT_CONFIG.staticDirectories),
105
141
  projectName: utils_validation_1.Joi.string().allow(''),
142
+ deploymentBranch: utils_validation_1.Joi.string().optional(),
106
143
  customFields: utils_validation_1.Joi.object().unknown().default(exports.DEFAULT_CONFIG.customFields),
107
144
  githubHost: utils_validation_1.Joi.string(),
145
+ githubPort: utils_validation_1.Joi.string(),
108
146
  plugins: utils_validation_1.Joi.array().items(PluginSchema).default(exports.DEFAULT_CONFIG.plugins),
109
147
  themes: utils_validation_1.Joi.array().items(ThemeSchema).default(exports.DEFAULT_CONFIG.themes),
110
148
  presets: utils_validation_1.Joi.array().items(PresetSchema).default(exports.DEFAULT_CONFIG.presets),
111
149
  themeConfig: utils_validation_1.Joi.object().unknown().default(exports.DEFAULT_CONFIG.themeConfig),
112
- scripts: utils_validation_1.Joi.array().items(utils_validation_1.Joi.string(), utils_validation_1.Joi.object({
150
+ scripts: utils_validation_1.Joi.array()
151
+ .items(utils_validation_1.Joi.string(), utils_validation_1.Joi.object({
113
152
  src: utils_validation_1.Joi.string().required(),
114
153
  async: utils_validation_1.Joi.bool(),
115
154
  defer: utils_validation_1.Joi.bool(),
116
155
  })
117
156
  // See https://github.com/facebook/docusaurus/issues/3378
118
- .unknown()),
157
+ .unknown())
158
+ .messages({
159
+ 'array.includes': '{#label} is invalid. A script must be a plain string (the src), or an object with at least a "src" property.',
160
+ })
161
+ .default(exports.DEFAULT_CONFIG.scripts),
119
162
  ssrTemplate: utils_validation_1.Joi.string(),
120
- stylesheets: utils_validation_1.Joi.array().items(utils_validation_1.Joi.string(), utils_validation_1.Joi.object({
163
+ stylesheets: utils_validation_1.Joi.array()
164
+ .items(utils_validation_1.Joi.string(), utils_validation_1.Joi.object({
121
165
  href: utils_validation_1.Joi.string().required(),
122
166
  type: utils_validation_1.Joi.string(),
123
- }).unknown()),
124
- clientModules: utils_validation_1.Joi.array().items(utils_validation_1.Joi.string()),
125
- tagline: utils_validation_1.Joi.string().allow(''),
126
- titleDelimiter: utils_validation_1.Joi.string().default('|'),
127
- noIndex: utils_validation_1.Joi.bool().default(false),
167
+ }).unknown())
168
+ .messages({
169
+ 'array.includes': '{#label} is invalid. A stylesheet must be a plain string (the href), or an object with at least a "href" property.',
170
+ })
171
+ .default(exports.DEFAULT_CONFIG.stylesheets),
172
+ clientModules: utils_validation_1.Joi.array()
173
+ .items(utils_validation_1.Joi.string())
174
+ .default(exports.DEFAULT_CONFIG.clientModules),
175
+ tagline: utils_validation_1.Joi.string().allow('').default(exports.DEFAULT_CONFIG.tagline),
176
+ titleDelimiter: utils_validation_1.Joi.string().default(exports.DEFAULT_CONFIG.titleDelimiter),
177
+ noIndex: utils_validation_1.Joi.bool().default(exports.DEFAULT_CONFIG.noIndex),
128
178
  webpack: utils_validation_1.Joi.object({
129
179
  jsLoader: utils_validation_1.Joi.alternatives()
130
180
  .try(utils_validation_1.Joi.string().equal('babel'), utils_validation_1.Joi.function())
@@ -134,20 +184,15 @@ exports.ConfigSchema = utils_validation_1.Joi.object({
134
184
  'docusaurus.configValidationWarning': 'Docusaurus config validation warning. Field {#label}: {#warningMessage}',
135
185
  });
136
186
  // TODO move to @docusaurus/utils-validation
137
- function validateConfig(config) {
187
+ function validateConfig(config, siteConfigPath) {
138
188
  const { error, warning, value } = exports.ConfigSchema.validate(config, {
139
189
  abortEarly: false,
140
190
  });
141
- utils_validation_1.printWarning(warning);
191
+ (0, utils_validation_1.printWarning)(warning);
142
192
  if (error) {
143
- utils_validation_1.logValidationBugReportHint();
144
- if (utils_validation_1.isValidationDisabledEscapeHatch) {
145
- console.error(error);
146
- return config;
147
- }
148
193
  const unknownFields = error.details.reduce((formattedError, err) => {
149
194
  if (err.type === 'object.unknown') {
150
- return `${formattedError}"${err.path}",`;
195
+ return `${formattedError}"${err.path.reduce((acc, cur) => typeof cur === 'string' ? `${acc}.${cur}` : `${acc}[${cur}]`)}",`;
151
196
  }
152
197
  return formattedError;
153
198
  }, '');
@@ -155,7 +200,7 @@ function validateConfig(config) {
155
200
  ? `${accumulatedErr}${err.message}\n`
156
201
  : accumulatedErr, '');
157
202
  formattedError = unknownFields
158
- ? `${formattedError}These field(s) (${unknownFields}) are not recognized in ${constants_1.DEFAULT_CONFIG_FILE_NAME}.\nIf you still want these fields to be in your configuration, put them in the "customFields" field.\nSee https://docusaurus.io/docs/docusaurus.config.js/#customfields`
203
+ ? `${formattedError}These field(s) (${unknownFields}) are not recognized in ${siteConfigPath}.\nIf you still want these fields to be in your configuration, put them in the "customFields" field.\nSee https://docusaurus.io/docs/api/docusaurus-config/#customfields`
159
204
  : formattedError;
160
205
  throw new Error(formattedError);
161
206
  }
@@ -0,0 +1,14 @@
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
+ export declare type HostPortOptions = {
8
+ host?: string;
9
+ port?: string;
10
+ };
11
+ export declare function getHostPort(options: HostPortOptions): Promise<{
12
+ host: string;
13
+ port: number | null;
14
+ }>;
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) Facebook, Inc. and its affiliates.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.getHostPort = void 0;
10
+ const tslib_1 = require("tslib");
11
+ const child_process_1 = require("child_process");
12
+ const logger_1 = tslib_1.__importDefault(require("@docusaurus/logger"));
13
+ const detect_port_1 = tslib_1.__importDefault(require("detect-port"));
14
+ const utils_1 = require("@docusaurus/utils");
15
+ const prompts_1 = tslib_1.__importDefault(require("prompts"));
16
+ const execOptions = {
17
+ encoding: 'utf8',
18
+ stdio: [/* stdin */ 'pipe', /* stdout */ 'pipe', /* stderr */ 'ignore'],
19
+ };
20
+ function clearConsole() {
21
+ process.stdout.write(process.platform === 'win32' ? '\x1B[2J\x1B[0f' : '\x1B[2J\x1B[3J\x1B[H');
22
+ }
23
+ function getProcessForPort(port) {
24
+ try {
25
+ const processId = (0, child_process_1.execSync)(`lsof -i:${port} -P -t -sTCP:LISTEN`, execOptions)
26
+ .split('\n')[0]
27
+ .trim();
28
+ const directory = (0, child_process_1.execSync)(`lsof -p ${processId} | awk '$4=="cwd" {for (i=9; i<=NF; i++) printf "%s ", $i}'`, execOptions).trim();
29
+ const command = (0, child_process_1.execSync)(`ps -o command -p ${processId} | sed -n 2p`, execOptions).replace(/\n$/, '');
30
+ return logger_1.default.interpolate `code=${command} subdue=${`(pid ${processId})`} in path=${directory}`;
31
+ }
32
+ catch {
33
+ return null;
34
+ }
35
+ }
36
+ /**
37
+ * Detects if program is running on port, and prompts user to choose another if
38
+ * port is already being used. This feature was heavily inspired by
39
+ * create-react-app and uses many of the same utility functions to implement it.
40
+ */
41
+ async function choosePort(host, defaultPort) {
42
+ try {
43
+ const port = await (0, detect_port_1.default)({ port: defaultPort, hostname: host });
44
+ if (port === defaultPort) {
45
+ return port;
46
+ }
47
+ const isRoot = process.getuid?.() === 0;
48
+ const isInteractive = process.stdout.isTTY;
49
+ const message = process.platform !== 'win32' && defaultPort < 1024 && !isRoot
50
+ ? `Admin permissions are required to run a server on a port below 1024.`
51
+ : `Something is already running on port ${defaultPort}.`;
52
+ if (!isInteractive) {
53
+ logger_1.default.error(message);
54
+ return null;
55
+ }
56
+ clearConsole();
57
+ const existingProcess = getProcessForPort(defaultPort);
58
+ const { shouldChangePort } = (await (0, prompts_1.default)({
59
+ type: 'confirm',
60
+ name: 'shouldChangePort',
61
+ message: logger_1.default.yellow(`${logger_1.default.bold('[WARNING]')} ${message}${existingProcess ? ` Probably:\n ${existingProcess}` : ''}
62
+
63
+ Would you like to run the app on another port instead?`),
64
+ initial: true,
65
+ }));
66
+ return shouldChangePort ? port : null;
67
+ }
68
+ catch (err) {
69
+ logger_1.default.error `Could not find an open port at ${host}.`;
70
+ throw err;
71
+ }
72
+ }
73
+ async function getHostPort(options) {
74
+ const host = options.host ?? 'localhost';
75
+ const basePort = options.port ? parseInt(options.port, 10) : utils_1.DEFAULT_PORT;
76
+ const port = await choosePort(host, basePort);
77
+ return { host, port };
78
+ }
79
+ exports.getHostPort = getHostPort;