@docusaurus/core 0.0.0-4630 → 0.0.0-4633

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 (38) hide show
  1. package/bin/beforeCli.mjs +2 -2
  2. package/bin/docusaurus.mjs +19 -11
  3. package/lib/choosePort.js +22 -30
  4. package/lib/client/serverEntry.js +7 -9
  5. package/lib/commands/build.js +2 -2
  6. package/lib/commands/clear.js +3 -3
  7. package/lib/commands/deploy.js +8 -7
  8. package/lib/commands/swizzle/actions.d.ts +23 -0
  9. package/lib/commands/swizzle/actions.js +102 -0
  10. package/lib/commands/swizzle/common.d.ts +33 -0
  11. package/lib/commands/swizzle/common.js +57 -0
  12. package/lib/commands/swizzle/components.d.ts +29 -0
  13. package/lib/commands/swizzle/components.js +165 -0
  14. package/lib/commands/swizzle/config.d.ts +10 -0
  15. package/lib/commands/swizzle/config.js +77 -0
  16. package/lib/commands/swizzle/context.d.ts +8 -0
  17. package/lib/commands/swizzle/context.js +30 -0
  18. package/lib/commands/swizzle/index.d.ts +8 -0
  19. package/lib/commands/swizzle/index.js +115 -0
  20. package/lib/commands/swizzle/prompts.d.ts +12 -0
  21. package/lib/commands/swizzle/prompts.js +110 -0
  22. package/lib/commands/swizzle/tables.d.ts +9 -0
  23. package/lib/commands/swizzle/tables.js +116 -0
  24. package/lib/commands/swizzle/themes.d.ts +20 -0
  25. package/lib/commands/swizzle/themes.js +105 -0
  26. package/lib/commands/writeTranslations.js +1 -1
  27. package/lib/server/brokenLinks.js +1 -1
  28. package/lib/server/configValidation.js +1 -1
  29. package/lib/server/plugins/init.d.ts +11 -1
  30. package/lib/server/plugins/init.js +8 -3
  31. package/lib/server/translations/translations.js +3 -2
  32. package/lib/server/translations/translationsExtractor.js +3 -5
  33. package/lib/server/versions/index.d.ts +0 -1
  34. package/lib/server/versions/index.js +3 -6
  35. package/lib/webpack/plugins/CleanWebpackPlugin.js +3 -3
  36. package/package.json +13 -11
  37. package/lib/commands/swizzle.d.ts +0 -9
  38. package/lib/commands/swizzle.js +0 -239
package/bin/beforeCli.mjs CHANGED
@@ -61,9 +61,9 @@ export default async function beforeCli() {
61
61
  notifier.config.set('lastUpdateCheck', 0);
62
62
  notifier.check();
63
63
  }
64
- } catch (e) {
64
+ } catch (err) {
65
65
  // Do not stop cli if this fails, see https://github.com/facebook/docusaurus/issues/5400
66
- logger.error(e);
66
+ logger.error(err);
67
67
  }
68
68
 
69
69
  /**
@@ -68,20 +68,28 @@ cli
68
68
 
69
69
  cli
70
70
  .command('swizzle [themeName] [componentName] [siteDir]')
71
- .description('Copy the theme files into website folder for customization.')
71
+ .description(
72
+ 'Wraps or ejects the original theme files into website folder for customization.',
73
+ )
74
+ .option(
75
+ '-w, --wrap',
76
+ 'Creates a wrapper around the original theme component.\nAllows rendering other components before/after the original theme component.',
77
+ )
78
+ .option(
79
+ '-e, --eject',
80
+ 'Ejects the full source code of the original theme component.\nAllows overriding the original component entirely with your own UI and logic.',
81
+ )
82
+ .option(
83
+ '-l, --list',
84
+ 'only list the available themes/components without further prompting (default: false)',
85
+ )
72
86
  .option(
73
- '--typescript',
87
+ '-t, --typescript',
74
88
  'copy TypeScript theme files when possible (default: false)',
75
89
  )
76
- .option('--danger', 'enable swizzle for internal component of themes')
77
- .action(async (themeName, componentName, siteDir, {typescript, danger}) => {
78
- swizzle(
79
- await resolveDir(siteDir),
80
- themeName,
81
- componentName,
82
- typescript,
83
- danger,
84
- );
90
+ .option('--danger', 'enable swizzle for unsafe component of themes')
91
+ .action(async (themeName, componentName, siteDir, options) => {
92
+ swizzle(await resolveDir(siteDir), themeName, componentName, options);
85
93
  });
86
94
 
87
95
  cli
package/lib/choosePort.js CHANGED
@@ -55,7 +55,7 @@ function getProcessForPort(port) {
55
55
  const command = getProcessCommand(processId);
56
56
  return logger_1.default.interpolate `code=${command} subdue=${`(pid ${processId})`} in path=${directory}`;
57
57
  }
58
- catch (e) {
58
+ catch {
59
59
  return null;
60
60
  }
61
61
  }
@@ -64,41 +64,33 @@ function getProcessForPort(port) {
64
64
  * to choose another if port is already being used
65
65
  */
66
66
  async function choosePort(host, defaultPort) {
67
- return (0, detect_port_1.default)({ port: defaultPort, hostname: host }).then((port) => new Promise((resolve) => {
67
+ try {
68
+ const port = await (0, detect_port_1.default)({ port: defaultPort, hostname: host });
68
69
  if (port === defaultPort) {
69
- resolve(port);
70
- return;
70
+ return port;
71
71
  }
72
72
  const message = process.platform !== 'win32' && defaultPort < 1024 && !(0, is_root_1.default)()
73
73
  ? `Admin permissions are required to run a server on a port below 1024.`
74
74
  : `Something is already running on port ${defaultPort}.`;
75
- if (isInteractive) {
76
- clearConsole();
77
- const existingProcess = getProcessForPort(defaultPort);
78
- const question = {
79
- type: 'confirm',
80
- name: 'shouldChangePort',
81
- message: logger_1.default.yellow(`${logger_1.default.bold('[WARNING]')} ${message}${existingProcess ? ` Probably:\n ${existingProcess}` : ''}
82
-
83
- Would you like to run the app on another port instead?`),
84
- initial: true,
85
- };
86
- (0, prompts_1.default)(question).then((answer) => {
87
- if (answer.shouldChangePort === true) {
88
- resolve(port);
89
- }
90
- else {
91
- resolve(null);
92
- }
93
- });
94
- }
95
- else {
75
+ if (!isInteractive) {
96
76
  logger_1.default.error(message);
97
- resolve(null);
77
+ return null;
98
78
  }
99
- }), (err) => {
100
- throw new Error(`Could not find an open port at ${host}.
101
- ${`Network error message: "${err.message || err}".`}`);
102
- });
79
+ clearConsole();
80
+ const existingProcess = getProcessForPort(defaultPort);
81
+ const { shouldChangePort } = await (0, prompts_1.default)({
82
+ type: 'confirm',
83
+ name: 'shouldChangePort',
84
+ message: logger_1.default.yellow(`${logger_1.default.bold('[WARNING]')} ${message}${existingProcess ? ` Probably:\n ${existingProcess}` : ''}
85
+
86
+ Would you like to run the app on another port instead?`),
87
+ initial: true,
88
+ });
89
+ return shouldChangePort ? port : null;
90
+ }
91
+ catch (err) {
92
+ logger_1.default.error `Could not find an open port at ${host}.`;
93
+ throw err;
94
+ }
103
95
  }
104
96
  exports.default = choosePort;
@@ -34,16 +34,15 @@ export default async function render(locals) {
34
34
  try {
35
35
  return await doRender(locals);
36
36
  }
37
- catch (e) {
38
- logger.error `Docusaurus Node/SSR could not render static page with path path=${locals.path} because of following error:
39
- ${e.stack}`;
37
+ catch (err) {
38
+ logger.error `Docusaurus server-side rendering could not render static page with path path=${locals.path}.`;
40
39
  const isNotDefinedErrorRegex = /(?:window|document|localStorage|navigator|alert|location|buffer|self) is not defined/i;
41
- if (isNotDefinedErrorRegex.test(e.message)) {
40
+ if (isNotDefinedErrorRegex.test(err.message)) {
42
41
  logger.info `It looks like you are using code that should run on the client-side only.
43
42
  To get around it, try using code=${'<BrowserOnly>'} (path=${'https://docusaurus.io/docs/docusaurus-core/#browseronly'}) or code=${'ExecutionEnvironment'} (path=${'https://docusaurus.io/docs/docusaurus-core/#executionenvironment'}).
44
43
  It might also require to wrap your client code in code=${'useEffect'} hook and/or import a third-party library dynamically (if any).`;
45
44
  }
46
- throw new Error('Server-side rendering fails due to the error above.');
45
+ throw err;
47
46
  }
48
47
  }
49
48
  // Renderer for static-site-generator-webpack-plugin (async rendering).
@@ -110,9 +109,8 @@ async function doRender(locals) {
110
109
  minifyJS: true,
111
110
  });
112
111
  }
113
- catch (e) {
114
- logger.error `Minification of page path=${locals.path} failed because of following error:
115
- ${e.stack}`;
116
- throw e;
112
+ catch (err) {
113
+ logger.error `Minification of page path=${locals.path} failed.`;
114
+ throw err;
117
115
  }
118
116
  }
@@ -41,9 +41,9 @@ forceTerminate = true) {
41
41
  isLastLocale,
42
42
  });
43
43
  }
44
- catch (e) {
44
+ catch (err) {
45
45
  logger_1.default.error `Unable to build website for locale name=${locale}.`;
46
- throw e;
46
+ throw err;
47
47
  }
48
48
  }
49
49
  const context = await (0, server_1.loadContext)(siteDir, {
@@ -19,9 +19,9 @@ async function removePath(entry) {
19
19
  await fs_extra_1.default.remove(entry.path);
20
20
  logger_1.default.success `Removed the ${entry.description} at path=${entry.path}.`;
21
21
  }
22
- catch (e) {
23
- logger_1.default.error `Could not remove the ${entry.description} at path=${entry.path}.
24
- ${e}`;
22
+ catch (err) {
23
+ logger_1.default.error `Could not remove the ${entry.description} at path=${entry.path}.`;
24
+ logger_1.default.error(err);
25
25
  }
26
26
  }
27
27
  async function clear(siteDir) {
@@ -28,9 +28,9 @@ function shellExecLog(cmd) {
28
28
  logger_1.default.info `code=${obfuscateGitPass(cmd)} subdue=${`code: ${result.code}`}`;
29
29
  return result;
30
30
  }
31
- catch (e) {
31
+ catch (err) {
32
32
  logger_1.default.error `code=${obfuscateGitPass(cmd)}`;
33
- throw e;
33
+ throw err;
34
34
  }
35
35
  }
36
36
  function buildSshUrl(githubHost, organizationName, projectName, githubPort) {
@@ -169,8 +169,9 @@ You can also set the deploymentBranch property in docusaurus.config.js .`);
169
169
  try {
170
170
  await fs_extra_1.default.copy(fromPath, toPath);
171
171
  }
172
- catch (error) {
173
- throw new Error(`Copying build assets from "${fromPath}" to "${toPath}" failed with error "${error}".`);
172
+ catch (err) {
173
+ logger_1.default.error `Copying build assets from path=${fromPath} to path=${toPath} failed.`;
174
+ throw err;
174
175
  }
175
176
  shellExecLog('git add --all');
176
177
  const commitMessage = process.env.CUSTOM_COMMIT_MESSAGE ||
@@ -200,9 +201,9 @@ You can also set the deploymentBranch property in docusaurus.config.js .`);
200
201
  try {
201
202
  await runDeploy(await (0, build_1.default)(siteDir, cliOptions, false));
202
203
  }
203
- catch (buildError) {
204
- logger_1.default.error(buildError.message);
205
- process.exit(1);
204
+ catch (err) {
205
+ logger_1.default.error('Deployment of the build output failed.');
206
+ throw err;
206
207
  }
207
208
  }
208
209
  else {
@@ -0,0 +1,23 @@
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 { SwizzleAction, SwizzleComponentConfig } from '@docusaurus/types';
8
+ import type { SwizzleOptions } from './common';
9
+ export declare const SwizzleActions: SwizzleAction[];
10
+ export declare function getAction(componentConfig: SwizzleComponentConfig, options: Pick<SwizzleOptions, 'wrap' | 'eject'>): Promise<SwizzleAction>;
11
+ export declare type ActionParams = {
12
+ siteDir: string;
13
+ themePath: string;
14
+ componentName: string;
15
+ };
16
+ export declare type ActionResult = {
17
+ createdFiles: string[];
18
+ };
19
+ export declare function eject({ siteDir, themePath, componentName, }: ActionParams): Promise<ActionResult>;
20
+ export declare function wrap({ siteDir, themePath, componentName: themeComponentName, typescript, importType, }: ActionParams & {
21
+ typescript: boolean;
22
+ importType?: 'original' | 'init';
23
+ }): Promise<ActionResult>;
@@ -0,0 +1,102 @@
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.wrap = exports.eject = exports.getAction = exports.SwizzleActions = void 0;
10
+ const tslib_1 = require("tslib");
11
+ const logger_1 = (0, tslib_1.__importDefault)(require("@docusaurus/logger"));
12
+ const fs_extra_1 = (0, tslib_1.__importDefault)(require("fs-extra"));
13
+ const path_1 = (0, tslib_1.__importDefault)(require("path"));
14
+ const lodash_1 = (0, tslib_1.__importDefault)(require("lodash"));
15
+ const utils_1 = require("@docusaurus/utils");
16
+ const prompts_1 = require("./prompts");
17
+ exports.SwizzleActions = ['wrap', 'eject'];
18
+ async function getAction(componentConfig, options) {
19
+ if (options.wrap) {
20
+ return 'wrap';
21
+ }
22
+ if (options.eject) {
23
+ return 'eject';
24
+ }
25
+ return (0, prompts_1.askSwizzleAction)(componentConfig);
26
+ }
27
+ exports.getAction = getAction;
28
+ async function isDir(dirPath) {
29
+ return ((await fs_extra_1.default.pathExists(dirPath)) && (await fs_extra_1.default.stat(dirPath)).isDirectory());
30
+ }
31
+ async function eject({ siteDir, themePath, componentName, }) {
32
+ const fromPath = path_1.default.join(themePath, componentName);
33
+ const isDirectory = await isDir(fromPath);
34
+ const globPattern = isDirectory
35
+ ? // do we really want to copy all components?
36
+ path_1.default.join(fromPath, '*')
37
+ : `${fromPath}.*`;
38
+ const globPatternPosix = (0, utils_1.posixPath)(globPattern);
39
+ const filesToCopy = await (0, utils_1.Globby)(globPatternPosix, {
40
+ ignore: ['**/*.{story,stories,test,tests}.{js,jsx,ts,tsx}'],
41
+ });
42
+ if (filesToCopy.length === 0) {
43
+ // This should never happen
44
+ throw new Error(logger_1.default.interpolate `No files to copy from path=${fromPath} with glob code=${globPatternPosix}`);
45
+ }
46
+ const toPath = isDirectory
47
+ ? path_1.default.join(siteDir, utils_1.THEME_PATH, componentName)
48
+ : path_1.default.join(siteDir, utils_1.THEME_PATH);
49
+ await fs_extra_1.default.ensureDir(toPath);
50
+ const createdFiles = await Promise.all(filesToCopy.map(async (sourceFile) => {
51
+ const fileName = path_1.default.basename(sourceFile);
52
+ const targetFile = path_1.default.join(toPath, fileName);
53
+ try {
54
+ await fs_extra_1.default.copy(sourceFile, targetFile, { overwrite: true });
55
+ }
56
+ catch (err) {
57
+ throw new Error(logger_1.default.interpolate `Could not copy file from ${sourceFile} to ${targetFile}`);
58
+ }
59
+ return targetFile;
60
+ }));
61
+ return { createdFiles };
62
+ }
63
+ exports.eject = eject;
64
+ async function wrap({ siteDir, themePath, componentName: themeComponentName, typescript, importType = 'original', }) {
65
+ const isDirectory = await isDir(path_1.default.join(themePath, themeComponentName));
66
+ // Top/Parent/ComponentName => ComponentName
67
+ const componentName = lodash_1.default.last(themeComponentName.split('/'));
68
+ const wrapperComponentName = `${componentName}Wrapper`;
69
+ const wrapperFileName = `${themeComponentName}${isDirectory ? '/index' : ''}${typescript ? '.tsx' : '.js'}`;
70
+ await fs_extra_1.default.ensureDir(path_1.default.resolve(siteDir, utils_1.THEME_PATH));
71
+ const toPath = path_1.default.resolve(siteDir, utils_1.THEME_PATH, wrapperFileName);
72
+ const content = typescript
73
+ ? `import React, {ComponentProps} from 'react';
74
+ import type ${componentName}Type from '@theme/${themeComponentName}';
75
+ import ${componentName} from '@theme-${importType}/${themeComponentName}';
76
+
77
+ type Props = ComponentProps<typeof ${componentName}Type>
78
+
79
+ export default function ${wrapperComponentName}(props: Props): JSX.Element {
80
+ return (
81
+ <>
82
+ <${componentName} {...props} />
83
+ </>
84
+ );
85
+ }
86
+ `
87
+ : `import React from 'react';
88
+ import ${componentName} from '@theme-${importType}/${themeComponentName}';
89
+
90
+ export default function ${wrapperComponentName}(props) {
91
+ return (
92
+ <>
93
+ <${componentName} {...props} />
94
+ </>
95
+ );
96
+ }
97
+ `;
98
+ await fs_extra_1.default.ensureDir(path_1.default.dirname(toPath));
99
+ await fs_extra_1.default.writeFile(toPath, content);
100
+ return { createdFiles: [toPath] };
101
+ }
102
+ exports.wrap = wrap;
@@ -0,0 +1,33 @@
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 { InitializedPlugin, SwizzleAction, SwizzleActionStatus } from '@docusaurus/types';
8
+ import type { NormalizedPluginConfig } from '../../server/plugins/init';
9
+ export declare const SwizzleActions: SwizzleAction[];
10
+ export declare const SwizzleActionsStatuses: SwizzleActionStatus[];
11
+ export declare const PartiallySafeHint: string;
12
+ export declare function actionStatusLabel(status: SwizzleActionStatus): string;
13
+ export declare function actionStatusColor(status: SwizzleActionStatus, str: string): string;
14
+ export declare function actionStatusSuffix(status: SwizzleActionStatus, options?: {
15
+ partiallySafe?: boolean;
16
+ }): string;
17
+ export declare type SwizzlePlugin = {
18
+ instance: InitializedPlugin;
19
+ plugin: NormalizedPluginConfig;
20
+ };
21
+ export declare type SwizzleContext = {
22
+ plugins: SwizzlePlugin[];
23
+ };
24
+ export declare type SwizzleOptions = {
25
+ typescript: boolean;
26
+ danger: boolean;
27
+ list: boolean;
28
+ wrap: boolean;
29
+ eject: boolean;
30
+ };
31
+ export declare function normalizeOptions(options: Partial<SwizzleOptions>): SwizzleOptions;
32
+ export declare function findStringIgnoringCase(str: string, values: string[]): string | undefined;
33
+ export declare function findClosestValue(str: string, values: string[], maxLevenshtein?: number): string | undefined;
@@ -0,0 +1,57 @@
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.findClosestValue = exports.findStringIgnoringCase = exports.normalizeOptions = exports.actionStatusSuffix = exports.actionStatusColor = exports.actionStatusLabel = exports.PartiallySafeHint = exports.SwizzleActionsStatuses = exports.SwizzleActions = void 0;
10
+ const tslib_1 = require("tslib");
11
+ const leven_1 = (0, tslib_1.__importDefault)(require("leven"));
12
+ const lodash_1 = (0, tslib_1.__importDefault)(require("lodash"));
13
+ const logger_1 = (0, tslib_1.__importDefault)(require("@docusaurus/logger"));
14
+ exports.SwizzleActions = ['wrap', 'eject'];
15
+ exports.SwizzleActionsStatuses = [
16
+ 'safe',
17
+ 'unsafe',
18
+ 'forbidden',
19
+ ];
20
+ exports.PartiallySafeHint = logger_1.default.red('*');
21
+ function actionStatusLabel(status) {
22
+ return lodash_1.default.capitalize(status);
23
+ }
24
+ exports.actionStatusLabel = actionStatusLabel;
25
+ const SwizzleActionStatusColors = {
26
+ safe: logger_1.default.green,
27
+ unsafe: logger_1.default.yellow,
28
+ forbidden: logger_1.default.red,
29
+ };
30
+ function actionStatusColor(status, str) {
31
+ const colorFn = SwizzleActionStatusColors[status];
32
+ return colorFn(str);
33
+ }
34
+ exports.actionStatusColor = actionStatusColor;
35
+ function actionStatusSuffix(status, options = {}) {
36
+ return ` (${actionStatusColor(status, actionStatusLabel(status))}${options.partiallySafe ? exports.PartiallySafeHint : ''})`;
37
+ }
38
+ exports.actionStatusSuffix = actionStatusSuffix;
39
+ function normalizeOptions(options) {
40
+ var _a, _b, _c, _d, _e;
41
+ return {
42
+ typescript: (_a = options.typescript) !== null && _a !== void 0 ? _a : false,
43
+ danger: (_b = options.danger) !== null && _b !== void 0 ? _b : false,
44
+ list: (_c = options.list) !== null && _c !== void 0 ? _c : false,
45
+ wrap: (_d = options.wrap) !== null && _d !== void 0 ? _d : false,
46
+ eject: (_e = options.eject) !== null && _e !== void 0 ? _e : false,
47
+ };
48
+ }
49
+ exports.normalizeOptions = normalizeOptions;
50
+ function findStringIgnoringCase(str, values) {
51
+ return values.find((v) => v.toLowerCase() === str.toLowerCase());
52
+ }
53
+ exports.findStringIgnoringCase = findStringIgnoringCase;
54
+ function findClosestValue(str, values, maxLevenshtein = 3) {
55
+ return values.find((v) => (0, leven_1.default)(v, str) <= maxLevenshtein);
56
+ }
57
+ exports.findClosestValue = findClosestValue;
@@ -0,0 +1,29 @@
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 { SwizzleAction, SwizzleActionStatus, SwizzleComponentConfig, SwizzleConfig } from '@docusaurus/types';
8
+ export declare type ThemeComponents = {
9
+ themeName: string;
10
+ all: string[];
11
+ getConfig: (component: string) => SwizzleComponentConfig;
12
+ getDescription: (component: string) => string;
13
+ getActionStatus: (component: string, action: SwizzleAction) => SwizzleActionStatus;
14
+ isSafeAction: (component: string, action: SwizzleAction) => boolean;
15
+ hasAnySafeAction: (component: string) => boolean;
16
+ hasAllSafeAction: (component: string) => boolean;
17
+ };
18
+ export declare function readComponentNames(themePath: string): Promise<string[]>;
19
+ export declare function listComponentNames(themeComponents: ThemeComponents): string;
20
+ export declare function getThemeComponents({ themeName, themePath, swizzleConfig, }: {
21
+ themeName: string;
22
+ themePath: string;
23
+ swizzleConfig: SwizzleConfig;
24
+ }): Promise<ThemeComponents>;
25
+ export declare function getComponentName({ componentNameParam, themeComponents, list, }: {
26
+ componentNameParam: string | undefined;
27
+ themeComponents: ThemeComponents;
28
+ list: boolean | undefined;
29
+ }): Promise<string>;
@@ -0,0 +1,165 @@
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.getComponentName = exports.getThemeComponents = exports.listComponentNames = exports.readComponentNames = void 0;
10
+ const tslib_1 = require("tslib");
11
+ const logger_1 = (0, tslib_1.__importDefault)(require("@docusaurus/logger"));
12
+ const fs_extra_1 = (0, tslib_1.__importDefault)(require("fs-extra"));
13
+ const path_1 = (0, tslib_1.__importDefault)(require("path"));
14
+ const lodash_1 = (0, tslib_1.__importDefault)(require("lodash"));
15
+ const utils_1 = require("@docusaurus/utils");
16
+ const prompts_1 = require("./prompts");
17
+ const common_1 = require("./common");
18
+ const tables_1 = require("./tables");
19
+ const actions_1 = require("./actions");
20
+ const formatComponentName = (componentName) => componentName.replace(/[/\\]index\.[jt]sx?/, '').replace(/\.[jt]sx?/, '');
21
+ const skipReadDirNames = ['__test__', '__tests__', '__mocks__', '__fixtures__'];
22
+ async function readComponentNames(themePath) {
23
+ if (!(await fs_extra_1.default.pathExists(themePath))) {
24
+ return [];
25
+ }
26
+ async function walk(dir) {
27
+ const files = await Promise.all((await fs_extra_1.default.readdir(dir)).flatMap(async (file) => {
28
+ const fullPath = path_1.default.join(dir, file);
29
+ const stat = await fs_extra_1.default.stat(fullPath);
30
+ const isDir = stat.isDirectory();
31
+ return { file, fullPath, isDir };
32
+ }));
33
+ return (await Promise.all(files.map(async (file) => {
34
+ if (file.isDir) {
35
+ if (skipReadDirNames.includes(file.file)) {
36
+ return [];
37
+ }
38
+ return walk(file.fullPath);
39
+ }
40
+ else if (
41
+ // TODO can probably be refactored
42
+ /(?<!\.d)\.[jt]sx?$/.test(file.fullPath) &&
43
+ !/(?<!\.d)\.(?:test|tests|story|stories)\.[jt]sx?$/.test(file.fullPath)) {
44
+ const componentName = formatComponentName((0, utils_1.posixPath)(path_1.default.relative(themePath, file.fullPath)));
45
+ return [{ ...file, componentName }];
46
+ }
47
+ return [];
48
+ }))).flat();
49
+ }
50
+ const componentFiles = await walk(themePath);
51
+ const componentFilesOrdered = lodash_1.default.orderBy(componentFiles, [(f) => f.componentName], ['asc']);
52
+ return componentFilesOrdered.map((f) => f.componentName);
53
+ }
54
+ exports.readComponentNames = readComponentNames;
55
+ function listComponentNames(themeComponents) {
56
+ if (themeComponents.all.length === 0) {
57
+ return 'No component to swizzle.';
58
+ }
59
+ return `${(0, tables_1.themeComponentsTable)(themeComponents)}
60
+
61
+ ${(0, tables_1.helpTables)()}
62
+ `;
63
+ }
64
+ exports.listComponentNames = listComponentNames;
65
+ async function getThemeComponents({ themeName, themePath, swizzleConfig, }) {
66
+ const FallbackSwizzleActionStatus = 'unsafe';
67
+ const FallbackSwizzleComponentDescription = 'N/A';
68
+ const FallbackSwizzleComponentConfig = {
69
+ actions: {
70
+ wrap: FallbackSwizzleActionStatus,
71
+ eject: FallbackSwizzleActionStatus,
72
+ },
73
+ description: FallbackSwizzleComponentDescription,
74
+ };
75
+ const allComponents = await readComponentNames(themePath);
76
+ function getConfig(component) {
77
+ var _a;
78
+ if (!allComponents.includes(component)) {
79
+ throw new Error(`Can't get component config: component doesn't exist: ${component}`);
80
+ }
81
+ return ((_a = swizzleConfig.components[component]) !== null && _a !== void 0 ? _a : FallbackSwizzleComponentConfig);
82
+ }
83
+ function getDescription(component) {
84
+ var _a;
85
+ return ((_a = getConfig(component).description) !== null && _a !== void 0 ? _a : FallbackSwizzleComponentDescription);
86
+ }
87
+ function getActionStatus(component, action) {
88
+ var _a;
89
+ return (_a = getConfig(component).actions[action]) !== null && _a !== void 0 ? _a : FallbackSwizzleActionStatus;
90
+ }
91
+ function isSafeAction(component, action) {
92
+ return getActionStatus(component, action) === 'safe';
93
+ }
94
+ function hasAllSafeAction(component) {
95
+ return actions_1.SwizzleActions.every((action) => isSafeAction(component, action));
96
+ }
97
+ function hasAnySafeAction(component) {
98
+ return actions_1.SwizzleActions.some((action) => isSafeAction(component, action));
99
+ }
100
+ // Present the safest components first
101
+ const orderedComponents = lodash_1.default.orderBy(allComponents, [
102
+ hasAllSafeAction,
103
+ (component) => isSafeAction(component, 'wrap'),
104
+ (component) => isSafeAction(component, 'eject'),
105
+ (component) => component,
106
+ ], ['desc', 'desc', 'desc', 'asc']);
107
+ return {
108
+ themeName,
109
+ all: orderedComponents,
110
+ getConfig,
111
+ getDescription,
112
+ getActionStatus,
113
+ isSafeAction,
114
+ hasAnySafeAction,
115
+ hasAllSafeAction,
116
+ };
117
+ }
118
+ exports.getThemeComponents = getThemeComponents;
119
+ // Returns a valid value if recovering is possible
120
+ function handleInvalidComponentNameParam({ componentNameParam, themeComponents, }) {
121
+ // Trying to recover invalid value
122
+ // We look for potential matches that only differ in casing.
123
+ const differentCaseMatch = (0, common_1.findStringIgnoringCase)(componentNameParam, themeComponents.all);
124
+ if (differentCaseMatch) {
125
+ logger_1.default.warn `Component name=${componentNameParam} doesn't exist.`;
126
+ logger_1.default.info `name=${differentCaseMatch} will be used instead of name=${componentNameParam}.`;
127
+ return differentCaseMatch;
128
+ }
129
+ // No recovery value is possible: print error
130
+ logger_1.default.error `Component name=${componentNameParam} not found.`;
131
+ const suggestion = (0, common_1.findClosestValue)(componentNameParam, themeComponents.all);
132
+ if (suggestion) {
133
+ logger_1.default.info `Did you mean name=${suggestion}? ${themeComponents.hasAnySafeAction(suggestion)
134
+ ? `Note: this component is an unsafe internal component and can only be swizzled with code=${'--danger'} or explicit confirmation.`
135
+ : ''}`;
136
+ }
137
+ else {
138
+ logger_1.default.info(listComponentNames(themeComponents));
139
+ }
140
+ return process.exit(1);
141
+ }
142
+ async function handleComponentNameParam({ componentNameParam, themeComponents, }) {
143
+ const isValidName = themeComponents.all.includes(componentNameParam);
144
+ if (!isValidName) {
145
+ return handleInvalidComponentNameParam({
146
+ componentNameParam,
147
+ themeComponents,
148
+ });
149
+ }
150
+ return componentNameParam;
151
+ }
152
+ async function getComponentName({ componentNameParam, themeComponents, list, }) {
153
+ if (list) {
154
+ logger_1.default.info(listComponentNames(themeComponents));
155
+ return process.exit(0);
156
+ }
157
+ const componentName = componentNameParam
158
+ ? await handleComponentNameParam({
159
+ componentNameParam,
160
+ themeComponents,
161
+ })
162
+ : await (0, prompts_1.askComponentName)(themeComponents);
163
+ return componentName;
164
+ }
165
+ exports.getComponentName = getComponentName;
@@ -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
+ import type { SwizzleConfig } from '@docusaurus/types';
8
+ import type { SwizzlePlugin } from './common';
9
+ export declare function normalizeSwizzleConfig(unsafeSwizzleConfig: unknown): SwizzleConfig;
10
+ export declare function getThemeSwizzleConfig(themeName: string, plugins: SwizzlePlugin[]): SwizzleConfig;