@docusaurus/core 2.1.0 → 2.3.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.
@@ -77,6 +77,10 @@ cli
77
77
  'copy TypeScript theme files when possible (default: false)',
78
78
  )
79
79
  .option('--danger', 'enable swizzle for unsafe component of themes')
80
+ .option(
81
+ '--config <config>',
82
+ 'path to Docusaurus config file (default: `[siteDir]/docusaurus.config.js`)',
83
+ )
80
84
  .action(swizzle);
81
85
 
82
86
  cli
@@ -100,6 +104,23 @@ cli
100
104
  )
101
105
  .action(deploy);
102
106
 
107
+ /**
108
+ * @param {string | undefined} value
109
+ * @returns {boolean | number}
110
+ */
111
+ function normalizePollValue(value) {
112
+ if (value === undefined || value === '') {
113
+ return false;
114
+ }
115
+
116
+ const parsedIntValue = Number.parseInt(value, 10);
117
+ if (!Number.isNaN(parsedIntValue)) {
118
+ return parsedIntValue;
119
+ }
120
+
121
+ return value === 'true';
122
+ }
123
+
103
124
  cli
104
125
  .command('start [siteDir]')
105
126
  .description('Start the development server.')
@@ -118,6 +139,7 @@ cli
118
139
  .option(
119
140
  '--poll [interval]',
120
141
  'use polling rather than watching for reload (default: false). Can specify a poll interval in milliseconds',
142
+ normalizePollValue,
121
143
  )
122
144
  .option(
123
145
  '--no-minify',
@@ -14,7 +14,17 @@ export function dispatchLifecycleAction(lifecycleAction, ...args) {
14
14
  });
15
15
  return () => callbacks.forEach((cb) => cb?.());
16
16
  }
17
- function scrollAfterNavigation(location) {
17
+ function scrollAfterNavigation({ location, previousLocation, }) {
18
+ if (!previousLocation) {
19
+ return; // no-op: use native browser feature
20
+ }
21
+ const samePathname = location.pathname === previousLocation.pathname;
22
+ const sameHash = location.hash === previousLocation.hash;
23
+ const sameSearch = location.search === previousLocation.search;
24
+ // Query-string changes: do not scroll to top/hash
25
+ if (samePathname && sameHash && !sameSearch) {
26
+ return;
27
+ }
18
28
  const { hash } = location;
19
29
  if (!hash) {
20
30
  window.scrollTo(0, 0);
@@ -28,9 +38,7 @@ function scrollAfterNavigation(location) {
28
38
  function ClientLifecyclesDispatcher({ children, location, previousLocation, }) {
29
39
  useLayoutEffect(() => {
30
40
  if (previousLocation !== location) {
31
- if (previousLocation) {
32
- scrollAfterNavigation(location);
33
- }
41
+ scrollAfterNavigation({ location, previousLocation });
34
42
  dispatchLifecycleAction('onRouteDidUpdate', { previousLocation, location });
35
43
  }
36
44
  }, [previousLocation, location]);
@@ -77,7 +77,7 @@ function Link({ isNavLink, to, href, activeClassName, isActive, 'data-noBrokenLi
77
77
  ioRef.current.observe(el);
78
78
  }
79
79
  };
80
- const onMouseEnter = () => {
80
+ const onInteractionEnter = () => {
81
81
  if (!preloaded.current && targetLink != null) {
82
82
  window.docusaurus.preload(targetLink);
83
83
  preloaded.current = true;
@@ -105,7 +105,7 @@ function Link({ isNavLink, to, href, activeClassName, isActive, 'data-noBrokenLi
105
105
  return isRegularHtmlLink ? (
106
106
  // eslint-disable-next-line jsx-a11y/anchor-has-content
107
107
  <a ref={innerRef} href={targetLink} {...(targetLinkUnprefixed &&
108
- !isInternal && { target: '_blank', rel: 'noopener noreferrer' })} {...props}/>) : (<LinkComponent {...props} onMouseEnter={onMouseEnter} innerRef={handleRef} to={targetLink}
108
+ !isInternal && { target: '_blank', rel: 'noopener noreferrer' })} {...props}/>) : (<LinkComponent {...props} onMouseEnter={onInteractionEnter} onTouchStart={onInteractionEnter} innerRef={handleRef} to={targetLink}
109
109
  // Avoid "React does not recognize the `activeClassName` prop on a DOM
110
110
  // element"
111
111
  {...(isNavLink && { isActive, activeClassName })}/>);
@@ -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 { useCallback } from 'react';
7
8
  import useDocusaurusContext from './useDocusaurusContext';
8
9
  import { hasProtocol } from './isInternalUrl';
9
10
  function addBaseUrl(siteUrl, baseUrl, url, { forcePrependBaseUrl = false, absolute = false } = {}) {
@@ -27,8 +28,9 @@ function addBaseUrl(siteUrl, baseUrl, url, { forcePrependBaseUrl = false, absolu
27
28
  }
28
29
  export function useBaseUrlUtils() {
29
30
  const { siteConfig: { baseUrl, url: siteUrl }, } = useDocusaurusContext();
31
+ const withBaseUrl = useCallback((url, options) => addBaseUrl(siteUrl, baseUrl, url, options), [siteUrl, baseUrl]);
30
32
  return {
31
- withBaseUrl: (url, options) => addBaseUrl(siteUrl, baseUrl, url, options),
33
+ withBaseUrl,
32
34
  };
33
35
  }
34
36
  export default function useBaseUrl(url, options = {}) {
@@ -131,7 +131,11 @@ async function buildLocale({ siteDir, locale, cliOptions, forceTerminate, isLast
131
131
  serverConfig = (0, webpack_merge_1.default)(serverConfig, {
132
132
  plugins: [
133
133
  new copy_webpack_plugin_1.default({
134
- patterns: staticDirectories.map((dir) => ({ from: dir, to: outDir })),
134
+ patterns: staticDirectories.map((dir) => ({
135
+ from: dir,
136
+ to: outDir,
137
+ toType: 'dir',
138
+ })),
135
139
  }),
136
140
  ],
137
141
  });
@@ -53,7 +53,7 @@ This behavior can have SEO impacts and create relative link issues.
53
53
  }
54
54
  // Source repo is the repo from where the command is invoked
55
55
  const sourceRepoUrl = shelljs_1.default
56
- .exec('git config --get remote.origin.url', { silent: true })
56
+ .exec('git remote get-url origin', { silent: true })
57
57
  .stdout.trim();
58
58
  // The source branch; defaults to the currently checked out branch
59
59
  const sourceBranch = process.env.CURRENT_BRANCH ??
@@ -33,7 +33,7 @@ async function eject({ siteDir, themePath, componentName, typescript, }) {
33
33
  const isDirectory = await isDir(fromPath);
34
34
  const globPattern = isDirectory
35
35
  ? // Do we really want to copy all components?
36
- path_1.default.join(fromPath, '*')
36
+ path_1.default.join(fromPath, '**/*')
37
37
  : `${fromPath}.*`;
38
38
  const globPatternPosix = (0, utils_1.posixPath)(globPattern);
39
39
  const filesToCopy = await (0, utils_1.Globby)(globPatternPosix, {
@@ -42,6 +42,7 @@ async function eject({ siteDir, themePath, componentName, typescript, }) {
42
42
  // When ejecting JS components, we want to avoid emitting TS files
43
43
  // In particular the .d.ts files that theme build output contains
44
44
  typescript ? null : '**/*.{d.ts,ts,tsx}',
45
+ '**/{__fixtures__,__tests__}/*',
45
46
  ]),
46
47
  });
47
48
  if (filesToCopy.length === 0) {
@@ -27,6 +27,7 @@ export declare type SwizzleCLIOptions = {
27
27
  list: boolean;
28
28
  wrap: boolean;
29
29
  eject: boolean;
30
+ config?: string;
30
31
  };
31
32
  export declare function normalizeOptions(options: Partial<SwizzleCLIOptions>): SwizzleCLIOptions;
32
33
  export declare function findStringIgnoringCase(str: string, values: string[]): string | undefined;
@@ -43,6 +43,7 @@ function normalizeOptions(options) {
43
43
  list: options.list ?? false,
44
44
  wrap: options.wrap ?? false,
45
45
  eject: options.eject ?? false,
46
+ config: options.config ?? undefined,
46
47
  };
47
48
  }
48
49
  exports.normalizeOptions = normalizeOptions;
@@ -15,6 +15,15 @@ export declare type ThemeComponents = {
15
15
  hasAnySafeAction: (component: string) => boolean;
16
16
  hasAllSafeAction: (component: string) => boolean;
17
17
  };
18
+ /**
19
+ * Expand a list of components to include and return parent folders.
20
+ * If a folder is not directly a component (no Folder/index.tsx file),
21
+ * we still want to be able to swizzle --eject that folder.
22
+ * See https://github.com/facebook/docusaurus/pull/7175#issuecomment-1103757218
23
+ *
24
+ * @param componentNames the original list of component names
25
+ */
26
+ export declare function getMissingIntermediateComponentFolderNames(componentNames: string[]): string[];
18
27
  export declare function readComponentNames(themePath: string): Promise<string[]>;
19
28
  export declare function listComponentNames(themeComponents: ThemeComponents): string;
20
29
  export declare function getThemeComponents({ themeName, themePath, swizzleConfig, }: {
@@ -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.getComponentName = exports.getThemeComponents = exports.listComponentNames = exports.readComponentNames = void 0;
9
+ exports.getComponentName = exports.getThemeComponents = exports.listComponentNames = exports.readComponentNames = exports.getMissingIntermediateComponentFolderNames = void 0;
10
10
  const tslib_1 = require("tslib");
11
11
  const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
12
12
  const path_1 = tslib_1.__importDefault(require("path"));
@@ -37,6 +37,7 @@ function getMissingIntermediateComponentFolderNames(componentNames) {
37
37
  const expandedComponentNames = lodash_1.default.uniq(componentNames.flatMap((componentName) => getAllIntermediatePaths(componentName)));
38
38
  return lodash_1.default.difference(expandedComponentNames, componentNames);
39
39
  }
40
+ exports.getMissingIntermediateComponentFolderNames = getMissingIntermediateComponentFolderNames;
40
41
  const skipReadDirNames = ['__test__', '__tests__', '__mocks__', '__fixtures__'];
41
42
  async function readComponentNames(themePath) {
42
43
  if (!(await fs_extra_1.default.pathExists(themePath))) {
@@ -4,5 +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 { SwizzleContext } from './common';
8
- export declare function initSwizzleContext(siteDir: string): Promise<SwizzleContext>;
7
+ import type { SwizzleCLIOptions, SwizzleContext } from './common';
8
+ export declare function initSwizzleContext(siteDir: string, options: SwizzleCLIOptions): Promise<SwizzleContext>;
@@ -10,8 +10,8 @@ exports.initSwizzleContext = void 0;
10
10
  const server_1 = require("../../server");
11
11
  const init_1 = require("../../server/plugins/init");
12
12
  const configs_1 = require("../../server/plugins/configs");
13
- async function initSwizzleContext(siteDir) {
14
- const context = await (0, server_1.loadContext)({ siteDir });
13
+ async function initSwizzleContext(siteDir, options) {
14
+ const context = await (0, server_1.loadContext)({ siteDir, config: options.config });
15
15
  const plugins = await (0, init_1.initPlugins)(context);
16
16
  const pluginConfigs = await (0, configs_1.loadPluginConfigs)(context);
17
17
  return {
@@ -62,7 +62,7 @@ async function swizzle(themeNameParam = undefined, componentNameParam = undefine
62
62
  const siteDir = await fs_extra_1.default.realpath(siteDirParam);
63
63
  const options = (0, common_1.normalizeOptions)(optionsParam);
64
64
  const { list, danger, typescript } = options;
65
- const { plugins } = await (0, context_1.initSwizzleContext)(siteDir);
65
+ const { plugins } = await (0, context_1.initSwizzleContext)(siteDir, options);
66
66
  const themeNames = (0, themes_1.getThemeNames)(plugins);
67
67
  if (list && !themeNameParam) {
68
68
  await listAllThemeComponents({ themeNames, plugins, typescript });
@@ -7,6 +7,6 @@
7
7
  import { Joi } from '@docusaurus/utils-validation';
8
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' | 'stylesheets' | 'scripts' | 'clientModules' | 'customFields' | 'themeConfig' | 'titleDelimiter' | 'noIndex' | 'tagline' | 'baseUrlIssueBanner' | 'staticDirectories'>;
10
+ export declare const DEFAULT_CONFIG: Pick<DocusaurusConfig, 'i18n' | 'onBrokenLinks' | 'onBrokenMarkdownLinks' | 'onDuplicateRoutes' | 'plugins' | 'themes' | 'presets' | 'headTags' | 'stylesheets' | 'scripts' | 'clientModules' | 'customFields' | 'themeConfig' | 'titleDelimiter' | 'noIndex' | 'tagline' | 'baseUrlIssueBanner' | 'staticDirectories' | 'markdown'>;
11
11
  export declare const ConfigSchema: Joi.ObjectSchema<DocusaurusConfig>;
12
12
  export declare function validateConfig(config: unknown, siteConfigPath: string): DocusaurusConfig;
@@ -24,6 +24,7 @@ exports.DEFAULT_CONFIG = {
24
24
  plugins: [],
25
25
  themes: [],
26
26
  presets: [],
27
+ headTags: [],
27
28
  stylesheets: [],
28
29
  scripts: [],
29
30
  clientModules: [],
@@ -34,6 +35,9 @@ exports.DEFAULT_CONFIG = {
34
35
  tagline: '',
35
36
  baseUrlIssueBanner: true,
36
37
  staticDirectories: [utils_1.DEFAULT_STATIC_DIR_NAME],
38
+ markdown: {
39
+ mermaid: false,
40
+ },
37
41
  };
38
42
  function createPluginSchema(theme) {
39
43
  return (utils_validation_1.Joi.alternatives()
@@ -101,24 +105,29 @@ const I18N_CONFIG_SCHEMA = utils_validation_1.Joi.object({
101
105
  })
102
106
  .optional()
103
107
  .default(exports.DEFAULT_I18N_CONFIG);
104
- const SiteUrlSchema = utils_validation_1.URISchema.required().custom((value, helpers) => {
108
+ const SiteUrlSchema = utils_validation_1.Joi.string()
109
+ .required()
110
+ .custom((value, helpers) => {
105
111
  try {
106
- const { pathname } = new URL(String(value));
112
+ const { pathname } = new URL(value);
107
113
  if (pathname !== '/') {
108
- helpers.warn('docusaurus.configValidationWarning', {
109
- warningMessage: `the url is not supposed to contain a sub-path like '${pathname}', please use the baseUrl field for sub-paths`,
110
- });
114
+ return helpers.error('docusaurus.subPathError', { pathname });
111
115
  }
112
116
  }
113
- catch { }
114
- return value;
115
- }, 'siteUrlCustomValidation');
117
+ catch {
118
+ return helpers.error('any.invalid');
119
+ }
120
+ return (0, utils_1.removeTrailingSlash)(value);
121
+ })
122
+ .messages({
123
+ 'any.invalid': '"{#value}" does not look like a valid URL. Make sure it has a protocol; for example, "https://example.com".',
124
+ 'docusaurus.subPathError': 'The url is not supposed to contain a sub-path like "{#pathname}". Please use the baseUrl field for sub-paths.',
125
+ });
116
126
  // TODO move to @docusaurus/utils-validation
117
127
  exports.ConfigSchema = utils_validation_1.Joi.object({
118
128
  baseUrl: utils_validation_1.Joi.string()
119
129
  .required()
120
- .regex(/\/$/m)
121
- .message('{{#label}} must be a string with a trailing slash.'),
130
+ .custom((value) => (0, utils_1.addLeadingSlash)((0, utils_1.addTrailingSlash)(value))),
122
131
  baseUrlIssueBanner: utils_validation_1.Joi.boolean().default(exports.DEFAULT_CONFIG.baseUrlIssueBanner),
123
132
  favicon: utils_validation_1.Joi.string().optional(),
124
133
  title: utils_validation_1.Joi.string().required(),
@@ -160,6 +169,17 @@ exports.ConfigSchema = utils_validation_1.Joi.object({
160
169
  })
161
170
  .default(exports.DEFAULT_CONFIG.scripts),
162
171
  ssrTemplate: utils_validation_1.Joi.string(),
172
+ headTags: utils_validation_1.Joi.array()
173
+ .items(utils_validation_1.Joi.object({
174
+ tagName: utils_validation_1.Joi.string().required(),
175
+ attributes: utils_validation_1.Joi.object()
176
+ .pattern(/[\w-]+/, utils_validation_1.Joi.string())
177
+ .required(),
178
+ }).unknown())
179
+ .messages({
180
+ 'array.includes': '{#label} is invalid. A headTag must be an object with at least a "tagName" and an "attributes" property.',
181
+ })
182
+ .default(exports.DEFAULT_CONFIG.headTags),
163
183
  stylesheets: utils_validation_1.Joi.array()
164
184
  .items(utils_validation_1.Joi.string(), utils_validation_1.Joi.object({
165
185
  href: utils_validation_1.Joi.string().required(),
@@ -180,6 +200,9 @@ exports.ConfigSchema = utils_validation_1.Joi.object({
180
200
  .try(utils_validation_1.Joi.string().equal('babel'), utils_validation_1.Joi.function())
181
201
  .optional(),
182
202
  }).optional(),
203
+ markdown: utils_validation_1.Joi.object({
204
+ mermaid: utils_validation_1.Joi.boolean().default(exports.DEFAULT_CONFIG.markdown.mermaid),
205
+ }).default(exports.DEFAULT_CONFIG.markdown),
183
206
  }).messages({
184
207
  'docusaurus.configValidationWarning': 'Docusaurus config validation warning. Field {#label}: {#warningMessage}',
185
208
  });
@@ -15,7 +15,7 @@ const path_1 = tslib_1.__importDefault(require("path"));
15
15
  * - Inject scripts/stylesheets
16
16
  */
17
17
  function createBootstrapPlugin({ siteDir, siteConfig, }) {
18
- const { stylesheets, scripts, clientModules: siteConfigClientModules, } = siteConfig;
18
+ const { stylesheets, scripts, headTags, clientModules: siteConfigClientModules, } = siteConfig;
19
19
  return {
20
20
  name: 'docusaurus-bootstrap-plugin',
21
21
  content: null,
@@ -46,7 +46,7 @@ function createBootstrapPlugin({ siteDir, siteConfig, }) {
46
46
  },
47
47
  });
48
48
  return {
49
- headTags: [...stylesheetsTags, ...scriptsTags],
49
+ headTags: [...headTags, ...stylesheetsTags, ...scriptsTags],
50
50
  };
51
51
  },
52
52
  };
@@ -87,6 +87,7 @@ function createMDXFallbackPlugin({ siteDir, siteConfig, }) {
87
87
  isMDXPartial: () => true,
88
88
  // External MDX files might have front matter, just disable the warning
89
89
  isMDXPartialFrontMatterWarningDisabled: true,
90
+ markdownConfig: siteConfig.markdown,
90
91
  };
91
92
  return {
92
93
  module: {
@@ -18,6 +18,7 @@ function indent(str) {
18
18
  return ` ${str.replace(/\n/g, `\n `)}`;
19
19
  }
20
20
  const chunkNameCache = new Map();
21
+ const chunkNameCount = new Map();
21
22
  /**
22
23
  * Generates a unique chunk name that can be used in the chunk registry.
23
24
  *
@@ -41,10 +42,15 @@ function genChunkName(modulePath, prefix, preferredName, shortId = process.env.N
41
42
  const shortHash = (0, utils_1.simpleHash)(modulePath, 3);
42
43
  str = `${preferredName}${shortHash}`;
43
44
  }
44
- const name = str === '/' ? 'index' : (0, utils_1.docuHash)(str);
45
+ const name = (0, utils_1.docuHash)(str);
45
46
  chunkName = prefix ? `${prefix}---${name}` : name;
46
47
  }
48
+ const seenCount = (chunkNameCount.get(chunkName) ?? 0) + 1;
49
+ if (seenCount > 1) {
50
+ chunkName += seenCount.toString(36);
51
+ }
47
52
  chunkNameCache.set(modulePath, chunkName);
53
+ chunkNameCount.set(chunkName, seenCount);
48
54
  }
49
55
  return chunkName;
50
56
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@docusaurus/core",
3
3
  "description": "Easy to Maintain Open Source Documentation Websites",
4
- "version": "2.1.0",
4
+ "version": "2.3.0",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
7
7
  "access": "public"
@@ -43,13 +43,13 @@
43
43
  "@babel/runtime": "^7.18.6",
44
44
  "@babel/runtime-corejs3": "^7.18.6",
45
45
  "@babel/traverse": "^7.18.8",
46
- "@docusaurus/cssnano-preset": "2.1.0",
47
- "@docusaurus/logger": "2.1.0",
48
- "@docusaurus/mdx-loader": "2.1.0",
46
+ "@docusaurus/cssnano-preset": "2.3.0",
47
+ "@docusaurus/logger": "2.3.0",
48
+ "@docusaurus/mdx-loader": "2.3.0",
49
49
  "@docusaurus/react-loadable": "5.5.2",
50
- "@docusaurus/utils": "2.1.0",
51
- "@docusaurus/utils-common": "2.1.0",
52
- "@docusaurus/utils-validation": "2.1.0",
50
+ "@docusaurus/utils": "2.3.0",
51
+ "@docusaurus/utils-common": "2.3.0",
52
+ "@docusaurus/utils-validation": "2.3.0",
53
53
  "@slorber/static-site-generator-webpack-plugin": "^4.0.7",
54
54
  "@svgr/webpack": "^6.2.1",
55
55
  "autoprefixer": "^10.4.7",
@@ -106,8 +106,8 @@
106
106
  "webpackbar": "^5.0.2"
107
107
  },
108
108
  "devDependencies": {
109
- "@docusaurus/module-type-aliases": "2.1.0",
110
- "@docusaurus/types": "2.1.0",
109
+ "@docusaurus/module-type-aliases": "2.3.0",
110
+ "@docusaurus/types": "2.3.0",
111
111
  "@types/detect-port": "^1.3.2",
112
112
  "@types/react-dom": "^18.0.6",
113
113
  "@types/react-router-config": "^5.0.6",
@@ -118,7 +118,7 @@
118
118
  "@types/webpack-bundle-analyzer": "^4.4.1",
119
119
  "react-test-renderer": "^17.0.2",
120
120
  "tmp-promise": "^3.0.3",
121
- "tree-node-cli": "^1.5.2"
121
+ "tree-node-cli": "^1.6.0"
122
122
  },
123
123
  "peerDependencies": {
124
124
  "react": "^16.8.4 || ^17.0.0",
@@ -127,5 +127,5 @@
127
127
  "engines": {
128
128
  "node": ">=16.14"
129
129
  },
130
- "gitHead": "be9b0942641184213485eba7fd75ceb0b328d3f4"
130
+ "gitHead": "ad477781bdca6a11fa9c6daef5048bdcec0ee37e"
131
131
  }