@docusaurus/plugin-content-docs 2.0.0-beta.17 → 2.0.0-beta.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/lib/categoryGeneratedIndex.js +0 -3
  2. package/lib/cli.js +3 -5
  3. package/lib/client/docsClientUtils.d.ts +3 -1
  4. package/lib/client/docsClientUtils.js +3 -3
  5. package/lib/client/index.d.ts +3 -1
  6. package/lib/docs.d.ts +4 -13
  7. package/lib/docs.js +7 -15
  8. package/lib/{docFrontMatter.d.ts → frontMatter.d.ts} +3 -1
  9. package/lib/{docFrontMatter.js → frontMatter.js} +0 -0
  10. package/lib/globalData.d.ts +2 -6
  11. package/lib/globalData.js +4 -8
  12. package/lib/lastUpdate.d.ts +4 -6
  13. package/lib/lastUpdate.js +13 -4
  14. package/lib/markdown/index.js +1 -1
  15. package/lib/markdown/linkify.js +4 -0
  16. package/lib/numberPrefix.js +16 -21
  17. package/lib/options.d.ts +3 -5
  18. package/lib/options.js +4 -3
  19. package/lib/sidebars/generator.js +33 -17
  20. package/lib/sidebars/index.js +13 -7
  21. package/lib/sidebars/postProcessor.js +11 -16
  22. package/lib/sidebars/processor.d.ts +3 -1
  23. package/lib/sidebars/processor.js +2 -2
  24. package/lib/sidebars/types.d.ts +13 -5
  25. package/lib/sidebars/utils.d.ts +15 -4
  26. package/lib/sidebars/utils.js +19 -23
  27. package/lib/sidebars/validation.d.ts +3 -1
  28. package/lib/sidebars/validation.js +1 -0
  29. package/lib/slug.js +3 -4
  30. package/lib/translations.js +19 -21
  31. package/lib/types.d.ts +9 -6
  32. package/lib/versions.js +3 -3
  33. package/package.json +10 -10
  34. package/src/categoryGeneratedIndex.ts +2 -6
  35. package/src/cli.ts +3 -5
  36. package/src/client/docsClientUtils.ts +3 -3
  37. package/src/client/index.ts +1 -1
  38. package/src/deps.d.ts +1 -1
  39. package/src/docs.ts +7 -25
  40. package/src/{docFrontMatter.ts → frontMatter.ts} +4 -4
  41. package/src/globalData.ts +5 -6
  42. package/src/index.ts +1 -2
  43. package/src/lastUpdate.ts +20 -8
  44. package/src/markdown/index.ts +1 -3
  45. package/src/markdown/linkify.ts +4 -0
  46. package/src/numberPrefix.ts +18 -28
  47. package/src/options.ts +6 -8
  48. package/src/plugin-content-docs.d.ts +12 -5
  49. package/src/sidebars/generator.ts +45 -22
  50. package/src/sidebars/index.ts +20 -13
  51. package/src/sidebars/postProcessor.ts +4 -9
  52. package/src/sidebars/processor.ts +4 -10
  53. package/src/sidebars/types.ts +5 -4
  54. package/src/sidebars/utils.ts +39 -43
  55. package/src/sidebars/validation.ts +4 -3
  56. package/src/slug.ts +3 -4
  57. package/src/translations.ts +24 -25
  58. package/src/types.ts +8 -7
  59. package/src/versions.ts +5 -5
@@ -11,9 +11,6 @@ const utils_1 = require("./sidebars/utils");
11
11
  const docs_1 = require("./docs");
12
12
  function getCategoryGeneratedIndexMetadata({ category, sidebarsUtils, docsById, }) {
13
13
  const { sidebarName, previous, next } = sidebarsUtils.getCategoryGeneratedIndexNavigation(category.link.permalink);
14
- if (!sidebarName) {
15
- throw new Error('unexpected');
16
- }
17
14
  return {
18
15
  title: category.link.title ?? category.label,
19
16
  description: category.link.description,
package/lib/cli.js CHANGED
@@ -26,8 +26,7 @@ async function createVersionedSidebarFile({ siteDir, pluginId, sidebarPath, vers
26
26
  if (shouldCreateVersionedSidebarFile) {
27
27
  const versionedSidebarsDir = (0, versions_1.getVersionedSidebarsDirPath)(siteDir, pluginId);
28
28
  const newSidebarFile = path_1.default.join(versionedSidebarsDir, `version-${version}-sidebars.json`);
29
- await fs_extra_1.default.ensureDir(path_1.default.dirname(newSidebarFile));
30
- await fs_extra_1.default.writeFile(newSidebarFile, `${JSON.stringify(sidebars, null, 2)}\n`, 'utf8');
29
+ await fs_extra_1.default.outputFile(newSidebarFile, `${JSON.stringify(sidebars, null, 2)}\n`, 'utf8');
31
30
  }
32
31
  }
33
32
  // Tests depend on non-default export for mocking.
@@ -47,7 +46,7 @@ async function cliDocsVersionCommand(version, siteDir, pluginId, options) {
47
46
  // Since we are going to create `version-${version}` folder, we need to make
48
47
  // sure it's a valid pathname.
49
48
  // eslint-disable-next-line no-control-regex
50
- if (/[<>:"|?*\x00-\x1F]/g.test(version)) {
49
+ if (/[<>:"|?*\x00-\x1F]/.test(version)) {
51
50
  throw new Error(`${pluginIdLogPrefix}: invalid version tag specified! Please ensure its a valid pathname too. Try something like: 1.0.0.`);
52
51
  }
53
52
  if (/^\.\.?$/.test(version)) {
@@ -83,8 +82,7 @@ async function cliDocsVersionCommand(version, siteDir, pluginId, options) {
83
82
  });
84
83
  // Update versions.json file.
85
84
  versions.unshift(version);
86
- await fs_extra_1.default.ensureDir(path_1.default.dirname(versionsJSONFile));
87
- await fs_extra_1.default.writeFile(versionsJSONFile, `${JSON.stringify(versions, null, 2)}\n`);
85
+ await fs_extra_1.default.outputFile(versionsJSONFile, `${JSON.stringify(versions, null, 2)}\n`);
88
86
  logger_1.default.success `name=${pluginIdLogPrefix}: version name=${version} created!`;
89
87
  }
90
88
  exports.cliDocsVersionCommand = cliDocsVersionCommand;
@@ -5,7 +5,9 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  import type { GlobalPluginData, GlobalVersion, GetActivePluginOptions, ActivePlugin, ActiveDocContext, DocVersionSuggestions } from '@docusaurus/plugin-content-docs/client';
8
- export declare function getActivePlugin(allPluginDatas: Record<string, GlobalPluginData>, pathname: string, options?: GetActivePluginOptions): ActivePlugin | undefined;
8
+ export declare function getActivePlugin(allPluginData: {
9
+ [pluginId: string]: GlobalPluginData;
10
+ }, pathname: string, options?: GetActivePluginOptions): ActivePlugin | undefined;
9
11
  export declare const getLatestVersion: (data: GlobalPluginData) => GlobalVersion;
10
12
  export declare const getActiveVersion: (data: GlobalPluginData, pathname: string) => GlobalVersion | undefined;
11
13
  export declare const getActiveDocContext: (data: GlobalPluginData, pathname: string) => ActiveDocContext;
@@ -12,8 +12,8 @@ const router_1 = require("@docusaurus/router");
12
12
  // get the data of the plugin that is currently "active"
13
13
  // ie the docs of that plugin are currently browsed
14
14
  // it is useful to support multiple docs plugin instances
15
- function getActivePlugin(allPluginDatas, pathname, options = {}) {
16
- const activeEntry = Object.entries(allPluginDatas)
15
+ function getActivePlugin(allPluginData, pathname, options = {}) {
16
+ const activeEntry = Object.entries(allPluginData)
17
17
  // Route sorting: '/android/foo' should match '/android' instead of '/'
18
18
  .sort((a, b) => b[1].path.localeCompare(a[1].path))
19
19
  .find(([, pluginData]) => !!(0, router_1.matchPath)(pathname, {
@@ -25,7 +25,7 @@ function getActivePlugin(allPluginDatas, pathname, options = {}) {
25
25
  ? { pluginId: activeEntry[0], pluginData: activeEntry[1] }
26
26
  : undefined;
27
27
  if (!activePlugin && options.failfast) {
28
- throw new Error(`Can't find active docs plugin for "${pathname}" pathname, while it was expected to be found. Maybe you tried to use a docs feature that can only be used on a docs-related page? Existing docs plugin paths are: ${Object.values(allPluginDatas)
28
+ throw new Error(`Can't find active docs plugin for "${pathname}" pathname, while it was expected to be found. Maybe you tried to use a docs feature that can only be used on a docs-related page? Existing docs plugin paths are: ${Object.values(allPluginData)
29
29
  .map((plugin) => plugin.path)
30
30
  .join(', ')}`);
31
31
  }
@@ -5,7 +5,9 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  import type { GlobalPluginData, GlobalVersion, ActivePlugin, ActiveDocContext, DocVersionSuggestions, GetActivePluginOptions } from '@docusaurus/plugin-content-docs/client';
8
- export declare const useAllDocsData: () => Record<string, GlobalPluginData>;
8
+ export declare const useAllDocsData: () => {
9
+ [pluginId: string]: GlobalPluginData;
10
+ };
9
11
  export declare const useDocsData: (pluginId: string | undefined) => GlobalPluginData;
10
12
  export declare const useActivePlugin: (options?: GetActivePluginOptions) => ActivePlugin | undefined;
11
13
  export declare const useActivePluginAndVersion: (options?: GetActivePluginOptions) => {
package/lib/docs.d.ts CHANGED
@@ -30,25 +30,16 @@ export declare function getMainDocId({ docs, sidebarsUtils, }: {
30
30
  sidebarsUtils: SidebarsUtils;
31
31
  }): string;
32
32
  export declare const isCategoryIndex: CategoryIndexMatcher;
33
- export declare function toCategoryIndexMatcherParam({ source, sourceDirName, }: Pick<DocMetadataBase, 'source' | 'sourceDirName'>): CategoryIndexMatcherParam;
34
33
  /**
35
34
  * `guides/sidebar/autogenerated.md` ->
36
35
  * `'autogenerated', '.md', ['sidebar', 'guides']`
37
36
  */
38
- export declare function splitPath(str: string): {
39
- /**
40
- * The list of directories, from lowest level to highest.
41
- * If there's no dir name, directories is ['.']
42
- */
43
- directories: string[];
44
- /** The file name, without extension */
45
- fileName: string;
46
- /** The extension, with a leading dot */
47
- extension: string;
48
- };
37
+ export declare function toCategoryIndexMatcherParam({ source, sourceDirName, }: Pick<DocMetadataBase, 'source' | 'sourceDirName'>): CategoryIndexMatcherParam;
49
38
  export declare function getDocIds(doc: DocMetadataBase): [string, string];
50
39
  export declare function createDocsByIdIndex<Doc extends {
51
40
  id: string;
52
41
  unversionedId: string;
53
- }>(docs: Doc[]): Record<string, Doc>;
42
+ }>(docs: Doc[]): {
43
+ [docId: string]: Doc;
44
+ };
54
45
  export {};
package/lib/docs.js CHANGED
@@ -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.createDocsByIdIndex = exports.getDocIds = exports.splitPath = exports.toCategoryIndexMatcherParam = exports.isCategoryIndex = exports.getMainDocId = exports.addDocNavigation = exports.processDocMetadata = exports.readVersionDocs = exports.readDocFile = void 0;
9
+ exports.createDocsByIdIndex = exports.getDocIds = exports.toCategoryIndexMatcherParam = exports.isCategoryIndex = exports.getMainDocId = exports.addDocNavigation = exports.processDocMetadata = exports.readVersionDocs = exports.readDocFile = void 0;
10
10
  const tslib_1 = require("tslib");
11
11
  const path_1 = tslib_1.__importDefault(require("path"));
12
12
  const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
@@ -17,7 +17,7 @@ const slug_1 = tslib_1.__importDefault(require("./slug"));
17
17
  const constants_1 = require("./constants");
18
18
  const versions_1 = require("./versions");
19
19
  const numberPrefix_1 = require("./numberPrefix");
20
- const docFrontMatter_1 = require("./docFrontMatter");
20
+ const frontMatter_1 = require("./frontMatter");
21
21
  const utils_2 = require("./sidebars/utils");
22
22
  async function readLastUpdateData(filePath, options) {
23
23
  const { showLastUpdateAuthor, showLastUpdateTime } = options;
@@ -61,7 +61,7 @@ function doProcessDocMetadata({ docFile, versionMetadata, context, options, }) {
61
61
  const { source, content, lastUpdate, contentPath, filePath } = docFile;
62
62
  const { siteDir, i18n } = context;
63
63
  const { frontMatter: unsafeFrontMatter, contentTitle, excerpt, } = (0, utils_1.parseMarkdownString)(content);
64
- const frontMatter = (0, docFrontMatter_1.validateDocFrontMatter)(unsafeFrontMatter);
64
+ const frontMatter = (0, frontMatter_1.validateDocFrontMatter)(unsafeFrontMatter);
65
65
  const { custom_edit_url: customEditURL,
66
66
  // Strip number prefixes by default
67
67
  // (01-MyFolder/01-MyDoc.md => MyFolder/MyDoc)
@@ -248,6 +248,10 @@ const isCategoryIndex = ({ fileName, directories, }) => {
248
248
  return eligibleDocIndexNames.includes(fileName.toLowerCase());
249
249
  };
250
250
  exports.isCategoryIndex = isCategoryIndex;
251
+ /**
252
+ * `guides/sidebar/autogenerated.md` ->
253
+ * `'autogenerated', '.md', ['sidebar', 'guides']`
254
+ */
251
255
  function toCategoryIndexMatcherParam({ source, sourceDirName, }) {
252
256
  // source + sourceDirName are always posix-style
253
257
  return {
@@ -257,18 +261,6 @@ function toCategoryIndexMatcherParam({ source, sourceDirName, }) {
257
261
  };
258
262
  }
259
263
  exports.toCategoryIndexMatcherParam = toCategoryIndexMatcherParam;
260
- /**
261
- * `guides/sidebar/autogenerated.md` ->
262
- * `'autogenerated', '.md', ['sidebar', 'guides']`
263
- */
264
- function splitPath(str) {
265
- return {
266
- fileName: path_1.default.parse(str).name,
267
- extension: path_1.default.parse(str).ext,
268
- directories: path_1.default.dirname(str).split(path_1.default.sep).reverse(),
269
- };
270
- }
271
- exports.splitPath = splitPath;
272
264
  // Return both doc ids
273
265
  // TODO legacy retro-compatibility due to old versioned sidebars using
274
266
  // versioned doc ids ("id" should be removed & "versionedId" should be renamed
@@ -5,4 +5,6 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  import type { DocFrontMatter } from './types';
8
- export declare function validateDocFrontMatter(frontMatter: Record<string, unknown>): DocFrontMatter;
8
+ export declare function validateDocFrontMatter(frontMatter: {
9
+ [key: string]: unknown;
10
+ }): DocFrontMatter;
File without changes
@@ -4,10 +4,6 @@
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 { Sidebars } from './sidebars/types';
8
- import type { CategoryGeneratedIndexMetadata, DocMetadata, LoadedVersion } from './types';
9
- import type { GlobalVersion, GlobalSidebar, GlobalDoc } from '@docusaurus/plugin-content-docs/client';
10
- export declare function toGlobalDataDoc(doc: DocMetadata): GlobalDoc;
11
- export declare function toGlobalDataGeneratedIndex(doc: CategoryGeneratedIndexMetadata): GlobalDoc;
12
- export declare function toGlobalSidebars(sidebars: Sidebars, version: LoadedVersion): Record<string, GlobalSidebar>;
7
+ import type { LoadedVersion } from './types';
8
+ import type { GlobalVersion } from '@docusaurus/plugin-content-docs/client';
13
9
  export declare function toGlobalDataVersion(version: LoadedVersion): GlobalVersion;
package/lib/globalData.js CHANGED
@@ -6,11 +6,10 @@
6
6
  * LICENSE file in the root directory of this source tree.
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.toGlobalDataVersion = exports.toGlobalSidebars = exports.toGlobalDataGeneratedIndex = exports.toGlobalDataDoc = void 0;
9
+ exports.toGlobalDataVersion = void 0;
10
10
  const tslib_1 = require("tslib");
11
11
  const lodash_1 = tslib_1.__importDefault(require("lodash"));
12
- const utils_1 = require("@docusaurus/utils");
13
- const utils_2 = require("./sidebars/utils");
12
+ const utils_1 = require("./sidebars/utils");
14
13
  function toGlobalDataDoc(doc) {
15
14
  return {
16
15
  id: doc.unversionedId,
@@ -18,7 +17,6 @@ function toGlobalDataDoc(doc) {
18
17
  sidebar: doc.sidebar,
19
18
  };
20
19
  }
21
- exports.toGlobalDataDoc = toGlobalDataDoc;
22
20
  function toGlobalDataGeneratedIndex(doc) {
23
21
  return {
24
22
  id: doc.slug,
@@ -26,9 +24,8 @@ function toGlobalDataGeneratedIndex(doc) {
26
24
  sidebar: doc.sidebar,
27
25
  };
28
26
  }
29
- exports.toGlobalDataGeneratedIndex = toGlobalDataGeneratedIndex;
30
27
  function toGlobalSidebars(sidebars, version) {
31
- const { getFirstLink } = (0, utils_2.createSidebarsUtils)(sidebars);
28
+ const { getFirstLink } = (0, utils_1.createSidebarsUtils)(sidebars);
32
29
  return lodash_1.default.mapValues(sidebars, (sidebar, sidebarId) => {
33
30
  const firstLink = getFirstLink(sidebarId);
34
31
  if (!firstLink) {
@@ -37,14 +34,13 @@ function toGlobalSidebars(sidebars, version) {
37
34
  return {
38
35
  link: {
39
36
  path: firstLink.type === 'generated-index'
40
- ? (0, utils_1.normalizeUrl)([version.versionPath, firstLink.slug])
37
+ ? firstLink.permalink
41
38
  : version.docs.find((doc) => doc.id === firstLink.id || doc.unversionedId === firstLink.id).permalink,
42
39
  label: firstLink.label,
43
40
  },
44
41
  };
45
42
  });
46
43
  }
47
- exports.toGlobalSidebars = toGlobalSidebars;
48
44
  function toGlobalDataVersion(version) {
49
45
  return {
50
46
  name: version.versionName,
@@ -4,9 +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
- declare type FileLastUpdateData = {
8
- timestamp?: number;
9
- author?: string;
10
- };
11
- export declare function getFileLastUpdate(filePath?: string): Promise<FileLastUpdateData | null>;
12
- export {};
7
+ export declare function getFileLastUpdate(filePath?: string): Promise<{
8
+ timestamp: number;
9
+ author: string;
10
+ } | null>;
package/lib/lastUpdate.js CHANGED
@@ -11,6 +11,7 @@ const tslib_1 = require("tslib");
11
11
  const logger_1 = tslib_1.__importDefault(require("@docusaurus/logger"));
12
12
  const utils_1 = require("@docusaurus/utils");
13
13
  let showedGitRequirementError = false;
14
+ let showedFileNotTrackedError = false;
14
15
  async function getFileLastUpdate(filePath) {
15
16
  if (!filePath) {
16
17
  return null;
@@ -25,12 +26,20 @@ async function getFileLastUpdate(filePath) {
25
26
  return { timestamp: result.timestamp, author: result.author };
26
27
  }
27
28
  catch (err) {
28
- if (err instanceof utils_1.GitNotFoundError && !showedGitRequirementError) {
29
- logger_1.default.warn('Sorry, the docs plugin last update options require Git.');
30
- showedGitRequirementError = true;
29
+ if (err instanceof utils_1.GitNotFoundError) {
30
+ if (!showedGitRequirementError) {
31
+ logger_1.default.warn('Sorry, the docs plugin last update options require Git.');
32
+ showedGitRequirementError = true;
33
+ }
34
+ }
35
+ else if (err instanceof utils_1.FileNotTrackedError) {
36
+ if (!showedFileNotTrackedError) {
37
+ logger_1.default.warn('Cannot infer the update date for some files, as they are not tracked by git.');
38
+ showedFileNotTrackedError = true;
39
+ }
31
40
  }
32
41
  else {
33
- logger_1.default.error(err);
42
+ logger_1.default.warn(err);
34
43
  }
35
44
  return null;
36
45
  }
@@ -11,6 +11,6 @@ function markdownLoader(source) {
11
11
  const fileString = source;
12
12
  const callback = this.async();
13
13
  const options = this.getOptions();
14
- return (callback && callback(null, (0, linkify_1.linkify)(fileString, this.resourcePath, options)));
14
+ return callback?.(null, (0, linkify_1.linkify)(fileString, this.resourcePath, options));
15
15
  }
16
16
  exports.default = markdownLoader;
@@ -11,6 +11,10 @@ const versions_1 = require("../versions");
11
11
  const utils_1 = require("@docusaurus/utils");
12
12
  function getVersion(filePath, options) {
13
13
  const versionFound = options.versionsMetadata.find((version) => (0, versions_1.getDocsDirPaths)(version).some((docsDirPath) => filePath.startsWith(docsDirPath)));
14
+ // At this point, this should never happen, because the MDX loaders' paths are
15
+ // literally using the version content paths; but if we allow sourcing content
16
+ // from outside the docs directory (through the `include` option, for example;
17
+ // is there a compelling use-case?), this would actually be testable
14
18
  if (!versionFound) {
15
19
  throw new Error(`Unexpected error: Markdown file at "${filePath}" does not belong to any docs version!`);
16
20
  }
@@ -8,33 +8,28 @@
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.stripPathNumberPrefixes = exports.stripNumberPrefix = exports.DisabledNumberPrefixParser = exports.DefaultNumberPrefixParser = void 0;
10
10
  // Best-effort to avoid parsing some patterns as number prefix
11
- const IgnoredPrefixPatterns = (() => {
12
- // ignore common date-like patterns: https://github.com/facebook/docusaurus/issues/4640
13
- const DateLikePrefixRegex = /^(?:\d{2}|\d{4})[-_.]\d{2}(?:[-_.](?:\d{2}|\d{4}))?.*$/;
14
- // ignore common versioning patterns: https://github.com/facebook/docusaurus/issues/4653
15
- // note: we could try to parse float numbers in filenames but that is
16
- // probably not worth it as a version such as "8.0" can be interpreted as both
17
- // a version and a float. User can configure her own NumberPrefixParser if
18
- // she wants 8.0 to be interpreted as a float
19
- const VersionLikePrefixRegex = /^\d+[-_.]\d+.*$/;
20
- return new RegExp(`${DateLikePrefixRegex.source}|${VersionLikePrefixRegex.source}`);
21
- })();
22
- const NumberPrefixRegex = /^(?<numberPrefix>\d+)(?<separator>\s*[-_.]+\s*)(?<suffix>.*)$/;
11
+ // ignore common date-like patterns: https://github.com/facebook/docusaurus/issues/4640
12
+ // ignore common versioning patterns: https://github.com/facebook/docusaurus/issues/4653
13
+ // Both of them would look like 7.0-foo or 2021-11-foo
14
+ // note: we could try to parse float numbers in filenames, but that is probably
15
+ // not worth it, as a version such as "8.0" can be interpreted as either a
16
+ // version or a float. User can configure her own NumberPrefixParser if she
17
+ // wants 8.0 to be interpreted as a float
18
+ const ignoredPrefixPattern = /^\d+[-_.]\d+/;
19
+ const numberPrefixPattern = /^(?<numberPrefix>\d+)\s*[-_.]+\s*(?<suffix>[^-_.\s].*)$/;
23
20
  // 0-myDoc => {filename: myDoc, numberPrefix: 0}
24
21
  // 003 - myDoc => {filename: myDoc, numberPrefix: 3}
25
22
  const DefaultNumberPrefixParser = (filename) => {
26
- if (IgnoredPrefixPatterns.exec(filename)) {
23
+ if (ignoredPrefixPattern.test(filename)) {
24
+ return { filename, numberPrefix: undefined };
25
+ }
26
+ const match = numberPrefixPattern.exec(filename);
27
+ if (!match) {
27
28
  return { filename, numberPrefix: undefined };
28
29
  }
29
- const match = NumberPrefixRegex.exec(filename);
30
- const cleanFileName = match?.groups?.suffix ?? filename;
31
- const numberPrefixString = match?.groups?.numberPrefix;
32
- const numberPrefix = numberPrefixString
33
- ? parseInt(numberPrefixString, 10)
34
- : undefined;
35
30
  return {
36
- filename: cleanFileName,
37
- numberPrefix,
31
+ filename: match.groups.suffix,
32
+ numberPrefix: parseInt(match.groups.numberPrefix, 10),
38
33
  };
39
34
  };
40
35
  exports.DefaultNumberPrefixParser = DefaultNumberPrefixParser;
package/lib/options.d.ts CHANGED
@@ -4,9 +4,7 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
- import type { PluginOptions } from '@docusaurus/plugin-content-docs';
8
- import { Joi } from '@docusaurus/utils-validation';
9
- import type { OptionValidationContext, ValidationResult } from '@docusaurus/types';
7
+ import type { PluginOptions, Options } from '@docusaurus/plugin-content-docs';
8
+ import type { OptionValidationContext } from '@docusaurus/types';
10
9
  export declare const DEFAULT_OPTIONS: Omit<PluginOptions, 'id' | 'sidebarPath'>;
11
- export declare const OptionsSchema: Joi.ObjectSchema<any>;
12
- export declare function validateOptions({ validate, options: userOptions, }: OptionValidationContext<PluginOptions>): ValidationResult<PluginOptions>;
10
+ export declare function validateOptions({ validate, options: userOptions, }: OptionValidationContext<Options, PluginOptions>): PluginOptions;
package/lib/options.js CHANGED
@@ -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.validateOptions = exports.OptionsSchema = exports.DEFAULT_OPTIONS = void 0;
9
+ exports.validateOptions = exports.DEFAULT_OPTIONS = void 0;
10
10
  const tslib_1 = require("tslib");
11
11
  const utils_validation_1 = require("@docusaurus/utils-validation");
12
12
  const utils_1 = require("@docusaurus/utils");
@@ -54,7 +54,7 @@ const VersionOptionsSchema = utils_validation_1.Joi.object({
54
54
  const VersionsOptionsSchema = utils_validation_1.Joi.object()
55
55
  .pattern(utils_validation_1.Joi.string().required(), VersionOptionsSchema)
56
56
  .default(exports.DEFAULT_OPTIONS.versions);
57
- exports.OptionsSchema = utils_validation_1.Joi.object({
57
+ const OptionsSchema = utils_validation_1.Joi.object({
58
58
  path: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.path),
59
59
  editUrl: utils_validation_1.Joi.alternatives().try(utils_validation_1.URISchema, utils_validation_1.Joi.function()),
60
60
  editCurrentVersion: utils_validation_1.Joi.boolean().default(exports.DEFAULT_OPTIONS.editCurrentVersion),
@@ -64,6 +64,7 @@ exports.OptionsSchema = utils_validation_1.Joi.object({
64
64
  // .allow('') ""
65
65
  .default(exports.DEFAULT_OPTIONS.routeBasePath),
66
66
  tagsBasePath: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.tagsBasePath),
67
+ // @ts-expect-error: deprecated
67
68
  homePageId: utils_validation_1.Joi.any().forbidden().messages({
68
69
  'any.unknown': 'The docs plugin option homePageId is not supported anymore. To make a doc the "home", please add "slug: /" in its front matter. See: https://docusaurus.io/docs/next/docs-introduction#home-page-docs',
69
70
  }),
@@ -121,7 +122,7 @@ function validateOptions({ validate, options: userOptions, }) {
121
122
  };
122
123
  }
123
124
  }
124
- const normalizedOptions = validate(exports.OptionsSchema, options);
125
+ const normalizedOptions = validate(OptionsSchema, options);
125
126
  if (normalizedOptions.admonitions) {
126
127
  normalizedOptions.remarkPlugins = normalizedOptions.remarkPlugins.concat([
127
128
  [remark_admonitions_1.default, normalizedOptions.admonitions],
@@ -27,7 +27,9 @@ const DefaultSidebarItemsGenerator = async ({ numberPrefixParser, isCategoryInde
27
27
  const getDoc = (docId) => {
28
28
  const doc = findDoc(docId);
29
29
  if (!doc) {
30
- throw new Error(`Can't find any doc with id=${docId}.\nAvailable doc ids:\n- ${Object.keys(docsById).join('\n- ')}`);
30
+ throw new Error(`Can't find any doc with ID ${docId}.
31
+ Available doc IDs:
32
+ - ${Object.keys(docsById).join('\n- ')}`);
31
33
  }
32
34
  return doc;
33
35
  };
@@ -103,8 +105,6 @@ const DefaultSidebarItemsGenerator = async ({ numberPrefixParser, isCategoryInde
103
105
  }
104
106
  function createCategoryItem(dir, fullPath, folderName) {
105
107
  const categoryMetadata = categoriesMetadata[(0, utils_1.posixPath)(path_1.default.join(autogenDir, fullPath))];
106
- const className = categoryMetadata?.className;
107
- const { filename, numberPrefix } = numberPrefixParser(folderName);
108
108
  const allItems = Object.entries(dir).map(([key, content]) => dirToItem(content, key, `${fullPath}/${key}`));
109
109
  // Try to match a doc inside the category folder,
110
110
  // using the "local id" (myDoc) or "qualified id" (dirName/myDoc)
@@ -120,35 +120,51 @@ const DefaultSidebarItemsGenerator = async ({ numberPrefixParser, isCategoryInde
120
120
  return isCategoryIndex((0, docs_1.toCategoryIndexMatcherParam)(doc));
121
121
  });
122
122
  }
123
- function getCategoryLinkedDocId() {
123
+ // In addition to the ID, this function also retrieves metadata of the
124
+ // linked doc that could be used as fallback values for category metadata
125
+ function getCategoryLinkedDocMetadata() {
124
126
  const link = categoryMetadata?.link;
125
- if (link !== undefined) {
126
- if (link && link.type === 'doc') {
127
- return findDocByLocalId(link.id)?.id || getDoc(link.id).id;
128
- }
127
+ if (link !== undefined && link?.type !== 'doc') {
129
128
  // If a link is explicitly specified, we won't apply conventions
130
129
  return undefined;
131
130
  }
132
- // Apply default convention to pick index.md, README.md or
133
- // <categoryName>.md as the category doc
134
- return findConventionalCategoryDocLink()?.id;
131
+ const id = link
132
+ ? findDocByLocalId(link.id)?.id ?? getDoc(link.id).id
133
+ : findConventionalCategoryDocLink()?.id;
134
+ if (!id) {
135
+ return undefined;
136
+ }
137
+ const doc = getDoc(id);
138
+ return {
139
+ id,
140
+ position: doc.sidebarPosition,
141
+ label: doc.frontMatter.sidebar_label ?? doc.title,
142
+ customProps: doc.frontMatter.sidebar_custom_props,
143
+ className: doc.frontMatter.sidebar_class_name,
144
+ };
135
145
  }
136
- const categoryLinkedDocId = getCategoryLinkedDocId();
137
- const link = categoryLinkedDocId
146
+ const categoryLinkedDoc = getCategoryLinkedDocMetadata();
147
+ const link = categoryLinkedDoc
138
148
  ? {
139
149
  type: 'doc',
140
- id: categoryLinkedDocId, // We "remap" a potentially "local id" to a "qualified id"
150
+ id: categoryLinkedDoc.id, // We "remap" a potentially "local id" to a "qualified id"
141
151
  }
142
152
  : categoryMetadata?.link;
143
153
  // If a doc is linked, remove it from the category subItems
144
- const items = allItems.filter((item) => !(item.type === 'doc' && item.id === categoryLinkedDocId));
154
+ const items = allItems.filter((item) => !(item.type === 'doc' && item.id === categoryLinkedDoc?.id));
155
+ const className = categoryMetadata?.className ?? categoryLinkedDoc?.className;
156
+ const customProps = categoryMetadata?.customProps ?? categoryLinkedDoc?.customProps;
157
+ const { filename, numberPrefix } = numberPrefixParser(folderName);
145
158
  return {
146
159
  type: 'category',
147
- label: categoryMetadata?.label ?? filename,
160
+ label: categoryMetadata?.label ?? categoryLinkedDoc?.label ?? filename,
148
161
  collapsible: categoryMetadata?.collapsible,
149
162
  collapsed: categoryMetadata?.collapsed,
150
- position: categoryMetadata?.position ?? numberPrefix,
163
+ position: categoryMetadata?.position ??
164
+ categoryLinkedDoc?.position ??
165
+ numberPrefix,
151
166
  source: folderName,
167
+ ...(customProps !== undefined && { customProps }),
152
168
  ...(className !== undefined && { className }),
153
169
  items,
154
170
  ...(link && { link }),
@@ -43,7 +43,7 @@ async function readCategoriesMetadata(contentPath) {
43
43
  });
44
44
  const categoryToFile = lodash_1.default.groupBy(categoryFiles, path_1.default.dirname);
45
45
  return (0, combine_promises_1.default)(lodash_1.default.mapValues(categoryToFile, async (files, folder) => {
46
- const [filePath] = files;
46
+ const filePath = files[0];
47
47
  if (files.length > 1) {
48
48
  logger_1.default.warn `There are more than one category metadata files for path=${folder}: ${files.join(', ')}. The behavior is undetermined.`;
49
49
  }
@@ -78,11 +78,17 @@ async function loadSidebarsFileUnsafe(sidebarFilePath) {
78
78
  exports.loadSidebarsFileUnsafe = loadSidebarsFileUnsafe;
79
79
  // Note: sidebarFilePath must be absolute, use resolveSidebarPathOption
80
80
  async function loadSidebars(sidebarFilePath, options) {
81
- const sidebarsConfig = await loadSidebarsFileUnsafe(sidebarFilePath);
82
- const normalizedSidebars = (0, normalization_1.normalizeSidebars)(sidebarsConfig);
83
- (0, validation_1.validateSidebars)(normalizedSidebars);
84
- const categoriesMetadata = await readCategoriesMetadata(options.version.contentPath);
85
- const processedSidebars = await (0, processor_1.processSidebars)(normalizedSidebars, categoriesMetadata, options);
86
- return (0, postProcessor_1.postProcessSidebars)(processedSidebars, options);
81
+ try {
82
+ const sidebarsConfig = await loadSidebarsFileUnsafe(sidebarFilePath);
83
+ const normalizedSidebars = (0, normalization_1.normalizeSidebars)(sidebarsConfig);
84
+ (0, validation_1.validateSidebars)(normalizedSidebars);
85
+ const categoriesMetadata = await readCategoriesMetadata(options.version.contentPath);
86
+ const processedSidebars = await (0, processor_1.processSidebars)(normalizedSidebars, categoriesMetadata, options);
87
+ return (0, postProcessor_1.postProcessSidebars)(processedSidebars, options);
88
+ }
89
+ catch (err) {
90
+ logger_1.default.error `Sidebars file at path=${sidebarFilePath} failed to be loaded.`;
91
+ throw err;
92
+ }
87
93
  }
88
94
  exports.loadSidebars = loadSidebars;
@@ -39,22 +39,17 @@ function postProcessSidebarItem(item, params) {
39
39
  if (!category.link) {
40
40
  throw new Error(`Sidebar category ${item.label} has neither any subitem nor a link. This makes this item not able to link to anything.`);
41
41
  }
42
- switch (category.link.type) {
43
- case 'doc':
44
- return {
45
- type: 'doc',
46
- label: category.label,
47
- id: category.link.id,
48
- };
49
- case 'generated-index':
50
- return {
51
- type: 'link',
52
- label: category.label,
53
- href: category.link.permalink,
54
- };
55
- default:
56
- throw new Error('Unexpected sidebar category link type');
57
- }
42
+ return category.link.type === 'doc'
43
+ ? {
44
+ type: 'doc',
45
+ label: category.label,
46
+ id: category.link.id,
47
+ }
48
+ : {
49
+ type: 'link',
50
+ label: category.label,
51
+ href: category.link.permalink,
52
+ };
58
53
  }
59
54
  // A non-collapsible category can't be collapsed!
60
55
  if (category.collapsible === false) {
@@ -5,4 +5,6 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  import type { NormalizedSidebars, ProcessedSidebars, SidebarProcessorParams, CategoryMetadataFile } from './types';
8
- export declare function processSidebars(unprocessedSidebars: NormalizedSidebars, categoriesMetadata: Record<string, CategoryMetadataFile>, params: SidebarProcessorParams): Promise<ProcessedSidebars>;
8
+ export declare function processSidebars(unprocessedSidebars: NormalizedSidebars, categoriesMetadata: {
9
+ [filePath: string]: CategoryMetadataFile;
10
+ }, params: SidebarProcessorParams): Promise<ProcessedSidebars>;
@@ -17,6 +17,7 @@ function toSidebarItemsGeneratorDoc(doc) {
17
17
  return lodash_1.default.pick(doc, [
18
18
  'id',
19
19
  'unversionedId',
20
+ 'title',
20
21
  'frontMatter',
21
22
  'source',
22
23
  'sourceDirName',
@@ -29,7 +30,7 @@ function toSidebarItemsGeneratorVersion(version) {
29
30
  // Handle the generation of autogenerated sidebar items and other
30
31
  // post-processing checks
31
32
  async function processSidebar(unprocessedSidebar, categoriesMetadata, params) {
32
- const { sidebarItemsGenerator, numberPrefixParser, docs, version, sidebarOptions, } = params;
33
+ const { sidebarItemsGenerator, numberPrefixParser, docs, version } = params;
33
34
  // Just a minor lazy transformation optimization
34
35
  const getSidebarItemsGeneratorDocsAndVersion = lodash_1.default.memoize(() => ({
35
36
  docs: docs.map(toSidebarItemsGeneratorDoc),
@@ -42,7 +43,6 @@ async function processSidebar(unprocessedSidebar, categoriesMetadata, params) {
42
43
  defaultSidebarItemsGenerator: generator_1.DefaultSidebarItemsGenerator,
43
44
  isCategoryIndex: docs_1.isCategoryIndex,
44
45
  ...getSidebarItemsGeneratorDocsAndVersion(),
45
- options: sidebarOptions,
46
46
  categoriesMetadata,
47
47
  });
48
48
  // Process again... weird but sidebar item generated might generate some