@docusaurus/plugin-content-docs 0.0.0-4546 → 0.0.0-4550

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@docusaurus/plugin-content-docs",
3
- "version": "0.0.0-4546",
3
+ "version": "0.0.0-4550",
4
4
  "description": "Docs plugin for Docusaurus.",
5
5
  "main": "lib/index.js",
6
6
  "exports": {
@@ -23,11 +23,11 @@
23
23
  },
24
24
  "license": "MIT",
25
25
  "dependencies": {
26
- "@docusaurus/core": "0.0.0-4546",
27
- "@docusaurus/logger": "0.0.0-4546",
28
- "@docusaurus/mdx-loader": "0.0.0-4546",
29
- "@docusaurus/utils": "0.0.0-4546",
30
- "@docusaurus/utils-validation": "0.0.0-4546",
26
+ "@docusaurus/core": "0.0.0-4550",
27
+ "@docusaurus/logger": "0.0.0-4550",
28
+ "@docusaurus/mdx-loader": "0.0.0-4550",
29
+ "@docusaurus/utils": "0.0.0-4550",
30
+ "@docusaurus/utils-validation": "0.0.0-4550",
31
31
  "combine-promises": "^1.1.0",
32
32
  "fs-extra": "^10.0.0",
33
33
  "import-fresh": "^3.2.2",
@@ -40,8 +40,8 @@
40
40
  "webpack": "^5.68.0"
41
41
  },
42
42
  "devDependencies": {
43
- "@docusaurus/module-type-aliases": "0.0.0-4546",
44
- "@docusaurus/types": "0.0.0-4546",
43
+ "@docusaurus/module-type-aliases": "0.0.0-4550",
44
+ "@docusaurus/types": "0.0.0-4550",
45
45
  "@types/js-yaml": "^4.0.0",
46
46
  "@types/picomatch": "^2.2.1",
47
47
  "commander": "^5.1.0",
@@ -57,5 +57,5 @@
57
57
  "engines": {
58
58
  "node": ">=14"
59
59
  },
60
- "gitHead": "f4dc68b452de796a2afbc90dfa03322c3c579b03"
60
+ "gitHead": "9eccadbbf68a877760b1ee7a42484df09cd9d862"
61
61
  }
package/src/cli.ts CHANGED
@@ -16,7 +16,7 @@ import type {
16
16
  PathOptions,
17
17
  SidebarOptions,
18
18
  } from '@docusaurus/plugin-content-docs';
19
- import {loadSidebarsFile, resolveSidebarPathOption} from './sidebars';
19
+ import {loadSidebarsFileUnsafe, resolveSidebarPathOption} from './sidebars';
20
20
  import {DEFAULT_PLUGIN_ID} from '@docusaurus/utils';
21
21
  import logger from '@docusaurus/logger';
22
22
 
@@ -34,7 +34,8 @@ async function createVersionedSidebarFile({
34
34
  // Load current sidebar and create a new versioned sidebars file (if needed).
35
35
  // Note: we don't need the sidebars file to be normalized: it's ok to let
36
36
  // plugin option changes to impact older, versioned sidebars
37
- const sidebars = await loadSidebarsFile(sidebarPath);
37
+ // We don't validate here, assuming the user has already built the version
38
+ const sidebars = await loadSidebarsFileUnsafe(sidebarPath);
38
39
 
39
40
  // Do not create a useless versioned sidebars file if sidebars file is empty
40
41
  // or sidebars are disabled/false)
@@ -0,0 +1,9 @@
1
+ # Sidebars
2
+
3
+ This part is very complicated and hard to navigate. Sidebars are loaded through the following steps:
4
+
5
+ 1. **Loading**. The sidebars file is read. Returns `SidebarsConfig`.
6
+ 2. **Normalization**. The shorthands are expanded. This step is very lenient about the sidebars' shapes. Returns `NormalizedSidebars`.
7
+ 3. **Validation**. The normalized sidebars are validated. This step happens after normalization, because the normalized sidebars are easier to validate, and allows us to repeatedly validate & generate in the future.
8
+ 4. **Generation**. This step is done through the "processor" (naming is hard). The `autogenerated` items are unwrapped. In the future, steps 3 and 4 may be repeatedly done until all autogenerated items are unwrapped. Returns `ProcessedSidebars`.
9
+ 5. **Post-processing**. Defaults are applied (collapsed states), category links are resolved, empty categories are flattened. Returns `Sidebars`.
@@ -6,12 +6,12 @@
6
6
  */
7
7
 
8
8
  import type {
9
- SidebarItem,
10
9
  SidebarItemDoc,
11
- SidebarItemCategory,
12
10
  SidebarItemsGenerator,
13
11
  SidebarItemsGeneratorDoc,
14
- SidebarItemCategoryLink,
12
+ NormalizedSidebarItemCategory,
13
+ NormalizedSidebarItem,
14
+ SidebarItemCategoryLinkConfig,
15
15
  } from './types';
16
16
  import {sortBy, last} from 'lodash';
17
17
  import {addTrailingSlash, posixPath} from '@docusaurus/utils';
@@ -48,7 +48,6 @@ export const DefaultSidebarItemsGenerator: SidebarItemsGenerator = async ({
48
48
  numberPrefixParser,
49
49
  isCategoryIndex,
50
50
  docs: allDocs,
51
- options,
52
51
  item: {dirName: autogenDir},
53
52
  categoriesMetadata,
54
53
  }) => {
@@ -125,7 +124,9 @@ export const DefaultSidebarItemsGenerator: SidebarItemsGenerator = async ({
125
124
  * Step 3. Recursively transform the tree-like structure to sidebar items.
126
125
  * (From a record to an array of items, akin to normalizing shorthand)
127
126
  */
128
- function generateSidebar(fsModel: Dir): Promise<WithPosition<SidebarItem>[]> {
127
+ function generateSidebar(
128
+ fsModel: Dir,
129
+ ): Promise<WithPosition<NormalizedSidebarItem>[]> {
129
130
  function createDocItem(id: string): WithPosition<SidebarItemDoc> {
130
131
  const {
131
132
  sidebarPosition: position,
@@ -145,7 +146,7 @@ export const DefaultSidebarItemsGenerator: SidebarItemsGenerator = async ({
145
146
  dir: Dir,
146
147
  fullPath: string,
147
148
  folderName: string,
148
- ): Promise<WithPosition<SidebarItemCategory>> {
149
+ ): Promise<WithPosition<NormalizedSidebarItemCategory>> {
149
150
  const categoryMetadata =
150
151
  categoriesMetadata[posixPath(path.join(autogenDir, fullPath))];
151
152
  const className = categoryMetadata?.className;
@@ -160,18 +161,19 @@ export const DefaultSidebarItemsGenerator: SidebarItemsGenerator = async ({
160
161
  // using the "local id" (myDoc) or "qualified id" (dirName/myDoc)
161
162
  function findDocByLocalId(localId: string): SidebarItemDoc | undefined {
162
163
  return allItems.find(
163
- (item) => item.type === 'doc' && getLocalDocId(item.id) === localId,
164
- ) as SidebarItemDoc | undefined;
164
+ (item): item is SidebarItemDoc =>
165
+ item.type === 'doc' && getLocalDocId(item.id) === localId,
166
+ );
165
167
  }
166
168
 
167
169
  function findConventionalCategoryDocLink(): SidebarItemDoc | undefined {
168
- return allItems.find((item) => {
170
+ return allItems.find((item): item is SidebarItemDoc => {
169
171
  if (item.type !== 'doc') {
170
172
  return false;
171
173
  }
172
174
  const doc = getDoc(item.id);
173
175
  return isCategoryIndex(toCategoryIndexMatcherParam(doc));
174
- }) as SidebarItemDoc | undefined;
176
+ });
175
177
  }
176
178
 
177
179
  function getCategoryLinkedDocId(): string | undefined {
@@ -190,13 +192,13 @@ export const DefaultSidebarItemsGenerator: SidebarItemsGenerator = async ({
190
192
 
191
193
  const categoryLinkedDocId = getCategoryLinkedDocId();
192
194
 
193
- const link: SidebarItemCategoryLink | undefined = categoryLinkedDocId
194
- ? {
195
- type: 'doc',
196
- id: categoryLinkedDocId, // We "remap" a potentially "local id" to a "qualified id"
197
- }
198
- : // TODO typing issue
199
- (categoryMetadata?.link as SidebarItemCategoryLink | undefined);
195
+ const link: SidebarItemCategoryLinkConfig | null | undefined =
196
+ categoryLinkedDocId
197
+ ? {
198
+ type: 'doc',
199
+ id: categoryLinkedDocId, // We "remap" a potentially "local id" to a "qualified id"
200
+ }
201
+ : categoryMetadata?.link;
200
202
 
201
203
  // If a doc is linked, remove it from the category subItems
202
204
  const items = allItems.filter(
@@ -206,9 +208,8 @@ export const DefaultSidebarItemsGenerator: SidebarItemsGenerator = async ({
206
208
  return {
207
209
  type: 'category',
208
210
  label: categoryMetadata?.label ?? filename,
209
- collapsible:
210
- categoryMetadata?.collapsible ?? options.sidebarCollapsible,
211
- collapsed: categoryMetadata?.collapsed ?? options.sidebarCollapsed,
211
+ collapsible: categoryMetadata?.collapsible,
212
+ collapsed: categoryMetadata?.collapsed,
212
213
  position: categoryMetadata?.position ?? numberPrefix,
213
214
  ...(className !== undefined && {className}),
214
215
  items,
@@ -219,7 +220,7 @@ export const DefaultSidebarItemsGenerator: SidebarItemsGenerator = async ({
219
220
  dir: Dir | null, // The directory item to be transformed.
220
221
  itemKey: string, // For docs, it's the doc ID; for categories, it's used to generate the next `relativePath`.
221
222
  fullPath: string, // `dir`'s full path relative to the autogen dir.
222
- ): Promise<WithPosition<SidebarItem>> {
223
+ ): Promise<WithPosition<NormalizedSidebarItem>> {
223
224
  return dir
224
225
  ? createCategoryItem(dir, fullPath, itemKey)
225
226
  : createDocItem(itemKey.substring(docIdPrefix.length));
@@ -238,7 +239,9 @@ export const DefaultSidebarItemsGenerator: SidebarItemsGenerator = async ({
238
239
  * consecutive sidebar slices (i.e. a whole category composed of multiple
239
240
  * autogenerated items)
240
241
  */
241
- function sortItems(sidebarItems: WithPosition<SidebarItem>[]): SidebarItem[] {
242
+ function sortItems(
243
+ sidebarItems: WithPosition<NormalizedSidebarItem>[],
244
+ ): NormalizedSidebarItem[] {
242
245
  const processedSidebarItems = sidebarItems.map((item) => {
243
246
  if (item.type === 'category') {
244
247
  return {...item, items: sortItems(item.items)};
@@ -7,13 +7,13 @@
7
7
 
8
8
  import fs from 'fs-extra';
9
9
  import importFresh from 'import-fresh';
10
- import type {SidebarsConfig, Sidebars, NormalizedSidebars} from './types';
11
- import type {NormalizeSidebarsParams} from '../types';
10
+ import type {SidebarsConfig, Sidebars, SidebarProcessorParams} from './types';
12
11
  import {validateSidebars, validateCategoryMetadataFile} from './validation';
13
12
  import {normalizeSidebars} from './normalization';
14
- import {processSidebars, type SidebarProcessorParams} from './processor';
13
+ import {processSidebars} from './processor';
14
+ import {postProcessSidebars} from './postProcessor';
15
15
  import path from 'path';
16
- import {createSlugger, Globby} from '@docusaurus/utils';
16
+ import {Globby} from '@docusaurus/utils';
17
17
  import logger from '@docusaurus/logger';
18
18
  import type {PluginOptions} from '@docusaurus/plugin-content-docs';
19
19
  import Yaml from 'js-yaml';
@@ -69,7 +69,7 @@ async function readCategoriesMetadata(contentPath: string) {
69
69
  );
70
70
  }
71
71
 
72
- async function loadSidebarsFileUnsafe(
72
+ export async function loadSidebarsFileUnsafe(
73
73
  sidebarFilePath: string | false | undefined,
74
74
  ): Promise<SidebarsConfig> {
75
75
  // false => no sidebars
@@ -93,37 +93,21 @@ async function loadSidebarsFileUnsafe(
93
93
  return importFresh(sidebarFilePath);
94
94
  }
95
95
 
96
- export async function loadSidebarsFile(
97
- sidebarFilePath: string | false | undefined,
98
- ): Promise<SidebarsConfig> {
99
- const sidebarsConfig = await loadSidebarsFileUnsafe(sidebarFilePath);
100
- validateSidebars(sidebarsConfig);
101
- return sidebarsConfig;
102
- }
103
-
104
- export async function loadNormalizedSidebars(
105
- sidebarFilePath: string | false | undefined,
106
- params: NormalizeSidebarsParams,
107
- ): Promise<NormalizedSidebars> {
108
- return normalizeSidebars(await loadSidebarsFile(sidebarFilePath), params);
109
- }
110
-
111
96
  // Note: sidebarFilePath must be absolute, use resolveSidebarPathOption
112
97
  export async function loadSidebars(
113
98
  sidebarFilePath: string | false | undefined,
114
- options: Omit<SidebarProcessorParams, 'categoriesMetadata'>,
99
+ options: SidebarProcessorParams,
115
100
  ): Promise<Sidebars> {
116
- const normalizeSidebarsParams: NormalizeSidebarsParams = {
117
- ...options.sidebarOptions,
118
- version: options.version,
119
- categoryLabelSlugger: createSlugger(),
120
- };
121
- const normalizedSidebars = await loadNormalizedSidebars(
122
- sidebarFilePath,
123
- normalizeSidebarsParams,
124
- );
101
+ const sidebarsConfig = await loadSidebarsFileUnsafe(sidebarFilePath);
102
+ const normalizedSidebars = normalizeSidebars(sidebarsConfig);
103
+ validateSidebars(normalizedSidebars);
125
104
  const categoriesMetadata = await readCategoriesMetadata(
126
105
  options.version.contentPath,
127
106
  );
128
- return processSidebars(normalizedSidebars, {...options, categoriesMetadata});
107
+ const processedSidebars = await processSidebars(
108
+ normalizedSidebars,
109
+ categoriesMetadata,
110
+ options,
111
+ );
112
+ return postProcessSidebars(processedSidebars, options);
129
113
  }
@@ -5,7 +5,6 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- import type {NormalizeSidebarsParams} from '../types';
9
8
  import type {
10
9
  NormalizedSidebarItem,
11
10
  NormalizedSidebar,
@@ -15,41 +14,16 @@ import type {
15
14
  SidebarItemConfig,
16
15
  SidebarConfig,
17
16
  SidebarsConfig,
18
- SidebarItemCategoryLink,
19
17
  NormalizedSidebarItemCategory,
20
18
  } from './types';
21
19
  import {isCategoriesShorthand} from './utils';
22
20
  import {mapValues} from 'lodash';
23
- import {normalizeUrl} from '@docusaurus/utils';
24
- import type {SidebarOptions} from '@docusaurus/plugin-content-docs';
25
-
26
- function normalizeCategoryLink(
27
- category: SidebarItemCategoryConfig,
28
- params: NormalizeSidebarsParams,
29
- ): SidebarItemCategoryLink | undefined {
30
- if (category.link?.type === 'generated-index') {
31
- // default slug logic can be improved
32
- const getDefaultSlug = () =>
33
- `/category/${params.categoryLabelSlugger.slug(category.label)}`;
34
- const slug = category.link.slug ?? getDefaultSlug();
35
- const permalink = normalizeUrl([params.version.versionPath, slug]);
36
- return {
37
- ...category.link,
38
- slug,
39
- permalink,
40
- };
41
- }
42
- return category.link;
43
- }
44
21
 
45
22
  function normalizeCategoriesShorthand(
46
23
  sidebar: SidebarCategoriesShorthand,
47
- options: SidebarOptions,
48
24
  ): SidebarItemCategoryConfig[] {
49
25
  return Object.entries(sidebar).map(([label, items]) => ({
50
26
  type: 'category',
51
- collapsed: options.sidebarCollapsed,
52
- collapsible: options.sidebarCollapsible,
53
27
  label,
54
28
  items,
55
29
  }));
@@ -61,7 +35,6 @@ function normalizeCategoriesShorthand(
61
35
  */
62
36
  export function normalizeItem(
63
37
  item: SidebarItemConfig,
64
- options: NormalizeSidebarsParams,
65
38
  ): NormalizedSidebarItem[] {
66
39
  if (typeof item === 'string') {
67
40
  return [
@@ -72,42 +45,41 @@ export function normalizeItem(
72
45
  ];
73
46
  }
74
47
  if (isCategoriesShorthand(item)) {
75
- return normalizeCategoriesShorthand(item, options).flatMap((subItem) =>
76
- normalizeItem(subItem, options),
48
+ return normalizeCategoriesShorthand(item).flatMap((subItem) =>
49
+ normalizeItem(subItem),
77
50
  );
78
51
  }
79
52
  if (item.type === 'category') {
80
- const link = normalizeCategoryLink(item, options);
53
+ if (typeof item.items !== 'undefined' && typeof item.items !== 'object') {
54
+ throw new Error(
55
+ `Invalid category ${JSON.stringify(
56
+ item,
57
+ )}: items must be an array of sidebar items or a category shorthand`,
58
+ );
59
+ }
81
60
  const normalizedCategory: NormalizedSidebarItemCategory = {
82
61
  ...item,
83
- link,
84
- items: (item.items ?? []).flatMap((subItem) =>
85
- normalizeItem(subItem, options),
86
- ),
87
- collapsible: item.collapsible ?? options.sidebarCollapsible,
88
- collapsed: item.collapsed ?? options.sidebarCollapsed,
62
+ items: Array.isArray(item.items)
63
+ ? item.items.flatMap((subItem) => normalizeItem(subItem))
64
+ : normalizeCategoriesShorthand(item.items).flatMap((subItem) =>
65
+ normalizeItem(subItem),
66
+ ),
89
67
  };
90
68
  return [normalizedCategory];
91
69
  }
92
70
  return [item];
93
71
  }
94
72
 
95
- function normalizeSidebar(
96
- sidebar: SidebarConfig,
97
- options: NormalizeSidebarsParams,
98
- ): NormalizedSidebar {
73
+ function normalizeSidebar(sidebar: SidebarConfig): NormalizedSidebar {
99
74
  const normalizedSidebar = Array.isArray(sidebar)
100
75
  ? sidebar
101
- : normalizeCategoriesShorthand(sidebar, options);
76
+ : normalizeCategoriesShorthand(sidebar);
102
77
 
103
- return normalizedSidebar.flatMap((subItem) =>
104
- normalizeItem(subItem, options),
105
- );
78
+ return normalizedSidebar.flatMap((subItem) => normalizeItem(subItem));
106
79
  }
107
80
 
108
81
  export function normalizeSidebars(
109
82
  sidebars: SidebarsConfig,
110
- params: NormalizeSidebarsParams,
111
83
  ): NormalizedSidebars {
112
- return mapValues(sidebars, (items) => normalizeSidebar(items, params));
84
+ return mapValues(sidebars, normalizeSidebar);
113
85
  }
@@ -0,0 +1,94 @@
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
+
8
+ import {normalizeUrl} from '@docusaurus/utils';
9
+ import type {
10
+ SidebarItem,
11
+ Sidebars,
12
+ SidebarProcessorParams,
13
+ ProcessedSidebarItemCategory,
14
+ ProcessedSidebarItem,
15
+ ProcessedSidebars,
16
+ SidebarItemCategoryLink,
17
+ } from './types';
18
+ import {mapValues} from 'lodash';
19
+
20
+ function normalizeCategoryLink(
21
+ category: ProcessedSidebarItemCategory,
22
+ params: SidebarProcessorParams,
23
+ ): SidebarItemCategoryLink | undefined {
24
+ if (category.link?.type === 'generated-index') {
25
+ // default slug logic can be improved
26
+ const getDefaultSlug = () =>
27
+ `/category/${params.categoryLabelSlugger.slug(category.label)}`;
28
+ const slug = category.link.slug ?? getDefaultSlug();
29
+ const permalink = normalizeUrl([params.version.versionPath, slug]);
30
+ return {
31
+ ...category.link,
32
+ slug,
33
+ permalink,
34
+ };
35
+ }
36
+ return category.link;
37
+ }
38
+
39
+ function postProcessSidebarItem(
40
+ item: ProcessedSidebarItem,
41
+ params: SidebarProcessorParams,
42
+ ): SidebarItem {
43
+ if (item.type === 'category') {
44
+ const category = {
45
+ ...item,
46
+ collapsed: item.collapsed ?? params.sidebarOptions.sidebarCollapsed,
47
+ collapsible: item.collapsible ?? params.sidebarOptions.sidebarCollapsible,
48
+ link: normalizeCategoryLink(item, params),
49
+ items: item.items.map((subItem) =>
50
+ postProcessSidebarItem(subItem, params),
51
+ ),
52
+ };
53
+ // If the current category doesn't have subitems, we render a normal link
54
+ // instead.
55
+ if (category.items.length === 0) {
56
+ if (!category.link) {
57
+ throw new Error(
58
+ `Sidebar category ${item.label} has neither any subitem nor a link. This makes this item not able to link to anything.`,
59
+ );
60
+ }
61
+ switch (category.link.type) {
62
+ case 'doc':
63
+ return {
64
+ type: 'doc',
65
+ label: category.label,
66
+ id: category.link.id,
67
+ };
68
+ case 'generated-index':
69
+ return {
70
+ type: 'link',
71
+ label: category.label,
72
+ href: category.link.permalink,
73
+ };
74
+ default:
75
+ throw new Error('Unexpected sidebar category link type');
76
+ }
77
+ }
78
+ // A non-collapsible category can't be collapsed!
79
+ if (category.collapsible === false) {
80
+ category.collapsed = false;
81
+ }
82
+ return category;
83
+ }
84
+ return item;
85
+ }
86
+
87
+ export function postProcessSidebars(
88
+ sidebars: ProcessedSidebars,
89
+ params: SidebarProcessorParams,
90
+ ): Sidebars {
91
+ return mapValues(sidebars, (sidebar) =>
92
+ sidebar.map((item) => postProcessSidebarItem(item, params)),
93
+ );
94
+ }
@@ -7,41 +7,23 @@
7
7
 
8
8
  import type {DocMetadataBase, VersionMetadata} from '../types';
9
9
  import type {
10
- Sidebars,
11
- Sidebar,
12
- SidebarItem,
13
10
  NormalizedSidebarItem,
14
11
  NormalizedSidebar,
15
12
  NormalizedSidebars,
16
- SidebarItemsGeneratorOption,
17
13
  SidebarItemsGeneratorDoc,
18
14
  SidebarItemsGeneratorVersion,
19
- NormalizedSidebarItemCategory,
20
- SidebarItemCategory,
21
15
  SidebarItemAutogenerated,
16
+ ProcessedSidebarItem,
17
+ ProcessedSidebar,
18
+ ProcessedSidebars,
19
+ SidebarProcessorParams,
22
20
  CategoryMetadataFile,
23
21
  } from './types';
24
- import {transformSidebarItems} from './utils';
25
22
  import {DefaultSidebarItemsGenerator} from './generator';
23
+ import {validateSidebars} from './validation';
26
24
  import {mapValues, memoize, pick} from 'lodash';
27
25
  import combinePromises from 'combine-promises';
28
- import {normalizeItem} from './normalization';
29
26
  import {isCategoryIndex} from '../docs';
30
- import type {Slugger} from '@docusaurus/utils';
31
- import type {
32
- NumberPrefixParser,
33
- SidebarOptions,
34
- } from '@docusaurus/plugin-content-docs';
35
-
36
- export type SidebarProcessorParams = {
37
- sidebarItemsGenerator: SidebarItemsGeneratorOption;
38
- numberPrefixParser: NumberPrefixParser;
39
- docs: DocMetadataBase[];
40
- version: VersionMetadata;
41
- categoryLabelSlugger: Slugger;
42
- sidebarOptions: SidebarOptions;
43
- categoriesMetadata: Record<string, CategoryMetadataFile>;
44
- };
45
27
 
46
28
  function toSidebarItemsGeneratorDoc(
47
29
  doc: DocMetadataBase,
@@ -66,15 +48,15 @@ function toSidebarItemsGeneratorVersion(
66
48
  // post-processing checks
67
49
  async function processSidebar(
68
50
  unprocessedSidebar: NormalizedSidebar,
51
+ categoriesMetadata: Record<string, CategoryMetadataFile>,
69
52
  params: SidebarProcessorParams,
70
- ): Promise<Sidebar> {
53
+ ): Promise<ProcessedSidebar> {
71
54
  const {
72
55
  sidebarItemsGenerator,
73
56
  numberPrefixParser,
74
57
  docs,
75
58
  version,
76
59
  sidebarOptions,
77
- categoriesMetadata,
78
60
  } = params;
79
61
 
80
62
  // Just a minor lazy transformation optimization
@@ -83,20 +65,9 @@ async function processSidebar(
83
65
  version: toSidebarItemsGeneratorVersion(version),
84
66
  }));
85
67
 
86
- async function processCategoryItem(
87
- item: NormalizedSidebarItemCategory,
88
- ): Promise<SidebarItemCategory> {
89
- return {
90
- ...item,
91
- items: (await Promise.all(item.items.map(processItem))).flat(),
92
- };
93
- }
94
-
95
68
  async function processAutoGeneratedItem(
96
69
  item: SidebarItemAutogenerated,
97
- ): Promise<SidebarItem[]> {
98
- // TODO the returned type can't be trusted in practice (generator can be
99
- // user-provided)
70
+ ): Promise<ProcessedSidebarItem[]> {
100
71
  const generatedItems = await sidebarItemsGenerator({
101
72
  item,
102
73
  numberPrefixParser,
@@ -106,50 +77,23 @@ async function processSidebar(
106
77
  options: sidebarOptions,
107
78
  categoriesMetadata,
108
79
  });
109
- // TODO validate generated items: user can generate bad items
110
-
111
- const generatedItemsNormalized = generatedItems.flatMap((generatedItem) =>
112
- normalizeItem(generatedItem, {...params, ...sidebarOptions}),
113
- );
114
-
115
80
  // Process again... weird but sidebar item generated might generate some
116
81
  // auto-generated items?
117
- return processItems(generatedItemsNormalized);
82
+ // TODO repeatedly process & unwrap autogenerated items until there are no
83
+ // more autogenerated items, or when loop count (e.g. 10) is reached
84
+ return processItems(generatedItems);
118
85
  }
119
86
 
120
87
  async function processItem(
121
88
  item: NormalizedSidebarItem,
122
- ): Promise<SidebarItem[]> {
89
+ ): Promise<ProcessedSidebarItem[]> {
123
90
  if (item.type === 'category') {
124
- // If the current category doesn't have subitems, we render a normal doc link instead.
125
- if (item.items.length === 0) {
126
- if (!item.link) {
127
- throw new Error(
128
- `Sidebar category ${item.label} has neither any subitem nor a link. This makes this item not able to link to anything.`,
129
- );
130
- }
131
- switch (item.link.type) {
132
- case 'doc':
133
- return [
134
- {
135
- type: 'doc',
136
- label: item.label,
137
- id: item.link.id,
138
- },
139
- ];
140
- case 'generated-index':
141
- return [
142
- {
143
- type: 'link',
144
- label: item.label,
145
- href: item.link.permalink,
146
- },
147
- ];
148
- default:
149
- throw new Error('Unexpected sidebar category link type');
150
- }
151
- }
152
- return [await processCategoryItem(item)];
91
+ return [
92
+ {
93
+ ...item,
94
+ items: (await Promise.all(item.items.map(processItem))).flat(),
95
+ },
96
+ ];
153
97
  }
154
98
  if (item.type === 'autogenerated') {
155
99
  return processAutoGeneratedItem(item);
@@ -159,32 +103,24 @@ async function processSidebar(
159
103
 
160
104
  async function processItems(
161
105
  items: NormalizedSidebarItem[],
162
- ): Promise<SidebarItem[]> {
106
+ ): Promise<ProcessedSidebarItem[]> {
163
107
  return (await Promise.all(items.map(processItem))).flat();
164
108
  }
165
109
 
166
110
  const processedSidebar = await processItems(unprocessedSidebar);
167
-
168
- const fixSidebarItemInconsistencies = (item: SidebarItem): SidebarItem => {
169
- // A non-collapsible category can't be collapsed!
170
- if (item.type === 'category' && !item.collapsible && item.collapsed) {
171
- return {
172
- ...item,
173
- collapsed: false,
174
- };
175
- }
176
- return item;
177
- };
178
- return transformSidebarItems(processedSidebar, fixSidebarItemInconsistencies);
111
+ return processedSidebar;
179
112
  }
180
113
 
181
114
  export async function processSidebars(
182
115
  unprocessedSidebars: NormalizedSidebars,
116
+ categoriesMetadata: Record<string, CategoryMetadataFile>,
183
117
  params: SidebarProcessorParams,
184
- ): Promise<Sidebars> {
185
- return combinePromises(
118
+ ): Promise<ProcessedSidebars> {
119
+ const processedSidebars = await combinePromises(
186
120
  mapValues(unprocessedSidebars, (unprocessedSidebar) =>
187
- processSidebar(unprocessedSidebar, params),
121
+ processSidebar(unprocessedSidebar, categoriesMetadata, params),
188
122
  ),
189
123
  );
124
+ validateSidebars(processedSidebars);
125
+ return processedSidebars;
190
126
  }