@docusaurus/plugin-content-docs 2.0.0-beta.15 → 2.0.0-beta.16
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/lib/cli.d.ts +1 -1
- package/lib/cli.js +18 -14
- package/lib/client/docsClientUtils.js +2 -2
- package/lib/client/index.d.ts +13 -1
- package/lib/client/index.js +66 -1
- package/lib/docFrontMatter.js +1 -0
- package/lib/docs.d.ts +2 -1
- package/lib/docs.js +23 -22
- package/lib/globalData.js +3 -2
- package/lib/index.js +11 -6
- package/lib/lastUpdate.js +14 -27
- package/lib/numberPrefix.js +7 -6
- package/lib/options.js +5 -2
- package/lib/props.js +15 -10
- package/lib/routes.js +6 -4
- package/lib/server-export.d.ts +8 -0
- package/lib/server-export.js +23 -0
- package/lib/sidebars/generator.d.ts +1 -9
- package/lib/sidebars/generator.js +26 -50
- package/lib/sidebars/index.d.ts +2 -5
- package/lib/sidebars/index.js +35 -20
- package/lib/sidebars/normalization.d.ts +2 -3
- package/lib/sidebars/normalization.js +17 -39
- package/lib/sidebars/postProcessor.d.ts +8 -0
- package/lib/sidebars/postProcessor.js +72 -0
- package/lib/sidebars/processor.d.ts +2 -13
- package/lib/sidebars/processor.js +25 -33
- package/lib/sidebars/types.d.ts +44 -10
- package/lib/sidebars/utils.js +53 -61
- package/lib/sidebars/validation.d.ts +2 -3
- package/lib/sidebars/validation.js +25 -30
- package/lib/slug.js +6 -8
- package/lib/tags.js +3 -2
- package/lib/translations.js +18 -17
- package/lib/types.d.ts +3 -6
- package/lib/versions.d.ts +25 -1
- package/lib/versions.js +25 -29
- package/package.json +19 -18
- package/src/cli.ts +25 -16
- package/src/client/docsClientUtils.ts +2 -2
- package/src/client/index.ts +97 -1
- package/src/docFrontMatter.ts +1 -0
- package/src/docs.ts +25 -20
- package/src/globalData.ts +2 -2
- package/src/index.ts +17 -7
- package/src/lastUpdate.ts +12 -33
- package/src/numberPrefix.ts +7 -6
- package/src/options.ts +5 -2
- package/src/plugin-content-docs.d.ts +16 -60
- package/src/props.ts +17 -12
- package/src/routes.ts +6 -4
- package/src/server-export.ts +24 -0
- package/src/sidebars/README.md +9 -0
- package/src/sidebars/generator.ts +50 -94
- package/src/sidebars/index.ts +50 -32
- package/src/sidebars/normalization.ts +22 -50
- package/src/sidebars/postProcessor.ts +94 -0
- package/src/sidebars/processor.ts +37 -66
- package/src/sidebars/types.ts +68 -10
- package/src/sidebars/utils.ts +63 -68
- package/src/sidebars/validation.ts +53 -53
- package/src/slug.ts +9 -10
- package/src/tags.ts +2 -2
- package/src/translations.ts +19 -16
- package/src/types.ts +3 -10
- package/src/versions.ts +30 -34
- package/lib/client/globalDataHooks.d.ts +0 -19
- package/lib/client/globalDataHooks.js +0 -76
- package/src/client/globalDataHooks.ts +0 -107
package/src/sidebars/index.ts
CHANGED
|
@@ -7,14 +7,18 @@
|
|
|
7
7
|
|
|
8
8
|
import fs from 'fs-extra';
|
|
9
9
|
import importFresh from 'import-fresh';
|
|
10
|
-
import type {SidebarsConfig, Sidebars,
|
|
11
|
-
import
|
|
12
|
-
import {validateSidebars} from './validation';
|
|
10
|
+
import type {SidebarsConfig, Sidebars, SidebarProcessorParams} from './types';
|
|
11
|
+
import {validateSidebars, validateCategoryMetadataFile} from './validation';
|
|
13
12
|
import {normalizeSidebars} from './normalization';
|
|
14
|
-
import {processSidebars
|
|
13
|
+
import {processSidebars} from './processor';
|
|
14
|
+
import {postProcessSidebars} from './postProcessor';
|
|
15
15
|
import path from 'path';
|
|
16
|
-
import {
|
|
16
|
+
import {Globby} from '@docusaurus/utils';
|
|
17
|
+
import logger from '@docusaurus/logger';
|
|
17
18
|
import type {PluginOptions} from '@docusaurus/plugin-content-docs';
|
|
19
|
+
import Yaml from 'js-yaml';
|
|
20
|
+
import _ from 'lodash';
|
|
21
|
+
import combinePromises from 'combine-promises';
|
|
18
22
|
|
|
19
23
|
export const DefaultSidebars: SidebarsConfig = {
|
|
20
24
|
defaultSidebar: [
|
|
@@ -38,9 +42,36 @@ export function resolveSidebarPathOption(
|
|
|
38
42
|
: sidebarPathOption;
|
|
39
43
|
}
|
|
40
44
|
|
|
41
|
-
function
|
|
45
|
+
async function readCategoriesMetadata(contentPath: string) {
|
|
46
|
+
const categoryFiles = await Globby('**/_category_.{json,yml,yaml}', {
|
|
47
|
+
cwd: contentPath,
|
|
48
|
+
});
|
|
49
|
+
const categoryToFile = _.groupBy(categoryFiles, path.dirname);
|
|
50
|
+
return combinePromises(
|
|
51
|
+
_.mapValues(categoryToFile, async (files, folder) => {
|
|
52
|
+
const [filePath] = files;
|
|
53
|
+
if (files.length > 1) {
|
|
54
|
+
logger.warn`There are more than one category metadata files for path=${folder}: ${files.join(
|
|
55
|
+
', ',
|
|
56
|
+
)}. The behavior is undetermined.`;
|
|
57
|
+
}
|
|
58
|
+
const content = await fs.readFile(
|
|
59
|
+
path.join(contentPath, filePath),
|
|
60
|
+
'utf-8',
|
|
61
|
+
);
|
|
62
|
+
try {
|
|
63
|
+
return validateCategoryMetadataFile(Yaml.load(content));
|
|
64
|
+
} catch (err) {
|
|
65
|
+
logger.error`The docs sidebar category metadata file path=${filePath} looks invalid!`;
|
|
66
|
+
throw err;
|
|
67
|
+
}
|
|
68
|
+
}),
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export async function loadSidebarsFileUnsafe(
|
|
42
73
|
sidebarFilePath: string | false | undefined,
|
|
43
|
-
): SidebarsConfig {
|
|
74
|
+
): Promise<SidebarsConfig> {
|
|
44
75
|
// false => no sidebars
|
|
45
76
|
if (sidebarFilePath === false) {
|
|
46
77
|
return DisabledSidebars;
|
|
@@ -54,7 +85,7 @@ function loadSidebarsFileUnsafe(
|
|
|
54
85
|
// Non-existent sidebars file: no sidebars
|
|
55
86
|
// Note: this edge case can happen on versioned docs, not current version
|
|
56
87
|
// We avoid creating empty versioned sidebars file with the CLI
|
|
57
|
-
if (!fs.
|
|
88
|
+
if (!(await fs.pathExists(sidebarFilePath))) {
|
|
58
89
|
return DisabledSidebars;
|
|
59
90
|
}
|
|
60
91
|
|
|
@@ -62,34 +93,21 @@ function loadSidebarsFileUnsafe(
|
|
|
62
93
|
return importFresh(sidebarFilePath);
|
|
63
94
|
}
|
|
64
95
|
|
|
65
|
-
export function loadSidebarsFile(
|
|
66
|
-
sidebarFilePath: string | false | undefined,
|
|
67
|
-
): SidebarsConfig {
|
|
68
|
-
const sidebarsConfig = loadSidebarsFileUnsafe(sidebarFilePath);
|
|
69
|
-
validateSidebars(sidebarsConfig);
|
|
70
|
-
return sidebarsConfig;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export function loadNormalizedSidebars(
|
|
74
|
-
sidebarFilePath: string | false | undefined,
|
|
75
|
-
params: NormalizeSidebarsParams,
|
|
76
|
-
): NormalizedSidebars {
|
|
77
|
-
return normalizeSidebars(loadSidebarsFile(sidebarFilePath), params);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
96
|
// Note: sidebarFilePath must be absolute, use resolveSidebarPathOption
|
|
81
97
|
export async function loadSidebars(
|
|
82
98
|
sidebarFilePath: string | false | undefined,
|
|
83
99
|
options: SidebarProcessorParams,
|
|
84
100
|
): Promise<Sidebars> {
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
101
|
+
const sidebarsConfig = await loadSidebarsFileUnsafe(sidebarFilePath);
|
|
102
|
+
const normalizedSidebars = normalizeSidebars(sidebarsConfig);
|
|
103
|
+
validateSidebars(normalizedSidebars);
|
|
104
|
+
const categoriesMetadata = await readCategoriesMetadata(
|
|
105
|
+
options.version.contentPath,
|
|
106
|
+
);
|
|
107
|
+
const processedSidebars = await processSidebars(
|
|
108
|
+
normalizedSidebars,
|
|
109
|
+
categoriesMetadata,
|
|
110
|
+
options,
|
|
93
111
|
);
|
|
94
|
-
return
|
|
112
|
+
return postProcessSidebars(processedSidebars, options);
|
|
95
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,17 @@ 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
|
-
import
|
|
23
|
-
import
|
|
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
|
-
}
|
|
20
|
+
import _ from 'lodash';
|
|
21
|
+
import logger from '@docusaurus/logger';
|
|
44
22
|
|
|
45
23
|
function normalizeCategoriesShorthand(
|
|
46
24
|
sidebar: SidebarCategoriesShorthand,
|
|
47
|
-
options: SidebarOptions,
|
|
48
25
|
): SidebarItemCategoryConfig[] {
|
|
49
26
|
return Object.entries(sidebar).map(([label, items]) => ({
|
|
50
27
|
type: 'category',
|
|
51
|
-
collapsed: options.sidebarCollapsed,
|
|
52
|
-
collapsible: options.sidebarCollapsible,
|
|
53
28
|
label,
|
|
54
29
|
items,
|
|
55
30
|
}));
|
|
@@ -61,31 +36,21 @@ function normalizeCategoriesShorthand(
|
|
|
61
36
|
*/
|
|
62
37
|
export function normalizeItem(
|
|
63
38
|
item: SidebarItemConfig,
|
|
64
|
-
options: NormalizeSidebarsParams,
|
|
65
39
|
): NormalizedSidebarItem[] {
|
|
66
40
|
if (typeof item === 'string') {
|
|
67
|
-
return [
|
|
68
|
-
{
|
|
69
|
-
type: 'doc',
|
|
70
|
-
id: item,
|
|
71
|
-
},
|
|
72
|
-
];
|
|
41
|
+
return [{type: 'doc', id: item}];
|
|
73
42
|
}
|
|
74
43
|
if (isCategoriesShorthand(item)) {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
);
|
|
44
|
+
// This will never throw anyways
|
|
45
|
+
return normalizeSidebar(item, 'sidebar items slice');
|
|
78
46
|
}
|
|
79
47
|
if (item.type === 'category') {
|
|
80
|
-
const link = normalizeCategoryLink(item, options);
|
|
81
48
|
const normalizedCategory: NormalizedSidebarItemCategory = {
|
|
82
49
|
...item,
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
50
|
+
items: normalizeSidebar(
|
|
51
|
+
item.items,
|
|
52
|
+
logger.interpolate`code=${'items'} of the category name=${item.label}`,
|
|
86
53
|
),
|
|
87
|
-
collapsible: item.collapsible ?? options.sidebarCollapsible,
|
|
88
|
-
collapsed: item.collapsed ?? options.sidebarCollapsed,
|
|
89
54
|
};
|
|
90
55
|
return [normalizedCategory];
|
|
91
56
|
}
|
|
@@ -94,20 +59,27 @@ export function normalizeItem(
|
|
|
94
59
|
|
|
95
60
|
function normalizeSidebar(
|
|
96
61
|
sidebar: SidebarConfig,
|
|
97
|
-
|
|
62
|
+
place: string,
|
|
98
63
|
): NormalizedSidebar {
|
|
64
|
+
if (!Array.isArray(sidebar) && !isCategoriesShorthand(sidebar)) {
|
|
65
|
+
throw new Error(
|
|
66
|
+
logger.interpolate`Invalid sidebar items collection code=${JSON.stringify(
|
|
67
|
+
sidebar,
|
|
68
|
+
)} in ${place}: it must either be an array of sidebar items or a shorthand notation (which doesn't contain a code=${'type'} property). See path=${'https://docusaurus.io/docs/sidebar/items'} for all valid syntaxes.`,
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
99
72
|
const normalizedSidebar = Array.isArray(sidebar)
|
|
100
73
|
? sidebar
|
|
101
|
-
: normalizeCategoriesShorthand(sidebar
|
|
74
|
+
: normalizeCategoriesShorthand(sidebar);
|
|
102
75
|
|
|
103
|
-
return normalizedSidebar.flatMap((subItem) =>
|
|
104
|
-
normalizeItem(subItem, options),
|
|
105
|
-
);
|
|
76
|
+
return normalizedSidebar.flatMap((subItem) => normalizeItem(subItem));
|
|
106
77
|
}
|
|
107
78
|
|
|
108
79
|
export function normalizeSidebars(
|
|
109
80
|
sidebars: SidebarsConfig,
|
|
110
|
-
params: NormalizeSidebarsParams,
|
|
111
81
|
): NormalizedSidebars {
|
|
112
|
-
return mapValues(sidebars, (
|
|
82
|
+
return _.mapValues(sidebars, (sidebar, id) =>
|
|
83
|
+
normalizeSidebar(sidebar, logger.interpolate`sidebar name=${id}`),
|
|
84
|
+
);
|
|
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 _ 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,44 +7,28 @@
|
|
|
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,
|
|
20
|
+
CategoryMetadataFile,
|
|
22
21
|
} from './types';
|
|
23
|
-
import {transformSidebarItems} from './utils';
|
|
24
22
|
import {DefaultSidebarItemsGenerator} from './generator';
|
|
25
|
-
import {
|
|
23
|
+
import {validateSidebars} from './validation';
|
|
24
|
+
import _ from 'lodash';
|
|
26
25
|
import combinePromises from 'combine-promises';
|
|
27
|
-
import {normalizeItem} from './normalization';
|
|
28
26
|
import {isCategoryIndex} from '../docs';
|
|
29
|
-
import type {Slugger} from '@docusaurus/utils';
|
|
30
|
-
import type {
|
|
31
|
-
NumberPrefixParser,
|
|
32
|
-
SidebarOptions,
|
|
33
|
-
} from '@docusaurus/plugin-content-docs';
|
|
34
|
-
|
|
35
|
-
export type SidebarProcessorParams = {
|
|
36
|
-
sidebarItemsGenerator: SidebarItemsGeneratorOption;
|
|
37
|
-
numberPrefixParser: NumberPrefixParser;
|
|
38
|
-
docs: DocMetadataBase[];
|
|
39
|
-
version: VersionMetadata;
|
|
40
|
-
categoryLabelSlugger: Slugger;
|
|
41
|
-
sidebarOptions: SidebarOptions;
|
|
42
|
-
};
|
|
43
27
|
|
|
44
28
|
function toSidebarItemsGeneratorDoc(
|
|
45
29
|
doc: DocMetadataBase,
|
|
46
30
|
): SidebarItemsGeneratorDoc {
|
|
47
|
-
return pick(doc, [
|
|
31
|
+
return _.pick(doc, [
|
|
48
32
|
'id',
|
|
49
33
|
'unversionedId',
|
|
50
34
|
'frontMatter',
|
|
@@ -57,14 +41,16 @@ function toSidebarItemsGeneratorDoc(
|
|
|
57
41
|
function toSidebarItemsGeneratorVersion(
|
|
58
42
|
version: VersionMetadata,
|
|
59
43
|
): SidebarItemsGeneratorVersion {
|
|
60
|
-
return pick(version, ['versionName', 'contentPath']);
|
|
44
|
+
return _.pick(version, ['versionName', 'contentPath']);
|
|
61
45
|
}
|
|
62
46
|
|
|
63
|
-
// Handle the generation of autogenerated sidebar items and other
|
|
47
|
+
// Handle the generation of autogenerated sidebar items and other
|
|
48
|
+
// post-processing checks
|
|
64
49
|
async function processSidebar(
|
|
65
50
|
unprocessedSidebar: NormalizedSidebar,
|
|
51
|
+
categoriesMetadata: Record<string, CategoryMetadataFile>,
|
|
66
52
|
params: SidebarProcessorParams,
|
|
67
|
-
): Promise<
|
|
53
|
+
): Promise<ProcessedSidebar> {
|
|
68
54
|
const {
|
|
69
55
|
sidebarItemsGenerator,
|
|
70
56
|
numberPrefixParser,
|
|
@@ -74,24 +60,14 @@ async function processSidebar(
|
|
|
74
60
|
} = params;
|
|
75
61
|
|
|
76
62
|
// Just a minor lazy transformation optimization
|
|
77
|
-
const getSidebarItemsGeneratorDocsAndVersion = memoize(() => ({
|
|
63
|
+
const getSidebarItemsGeneratorDocsAndVersion = _.memoize(() => ({
|
|
78
64
|
docs: docs.map(toSidebarItemsGeneratorDoc),
|
|
79
65
|
version: toSidebarItemsGeneratorVersion(version),
|
|
80
66
|
}));
|
|
81
67
|
|
|
82
|
-
async function processCategoryItem(
|
|
83
|
-
item: NormalizedSidebarItemCategory,
|
|
84
|
-
): Promise<SidebarItemCategory> {
|
|
85
|
-
return {
|
|
86
|
-
...item,
|
|
87
|
-
items: (await Promise.all(item.items.map(processItem))).flat(),
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
|
|
91
68
|
async function processAutoGeneratedItem(
|
|
92
69
|
item: SidebarItemAutogenerated,
|
|
93
|
-
): Promise<
|
|
94
|
-
// TODO the returned type can't be trusted in practice (generator can be user-provided)
|
|
70
|
+
): Promise<ProcessedSidebarItem[]> {
|
|
95
71
|
const generatedItems = await sidebarItemsGenerator({
|
|
96
72
|
item,
|
|
97
73
|
numberPrefixParser,
|
|
@@ -99,22 +75,25 @@ async function processSidebar(
|
|
|
99
75
|
isCategoryIndex,
|
|
100
76
|
...getSidebarItemsGeneratorDocsAndVersion(),
|
|
101
77
|
options: sidebarOptions,
|
|
78
|
+
categoriesMetadata,
|
|
102
79
|
});
|
|
103
|
-
//
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
);
|
|
108
|
-
|
|
109
|
-
// Process again... weird but sidebar item generated might generate some auto-generated items?
|
|
110
|
-
return processItems(generatedItemsNormalized);
|
|
80
|
+
// Process again... weird but sidebar item generated might generate some
|
|
81
|
+
// auto-generated items?
|
|
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);
|
|
111
85
|
}
|
|
112
86
|
|
|
113
87
|
async function processItem(
|
|
114
88
|
item: NormalizedSidebarItem,
|
|
115
|
-
): Promise<
|
|
89
|
+
): Promise<ProcessedSidebarItem[]> {
|
|
116
90
|
if (item.type === 'category') {
|
|
117
|
-
return [
|
|
91
|
+
return [
|
|
92
|
+
{
|
|
93
|
+
...item,
|
|
94
|
+
items: (await Promise.all(item.items.map(processItem))).flat(),
|
|
95
|
+
},
|
|
96
|
+
];
|
|
118
97
|
}
|
|
119
98
|
if (item.type === 'autogenerated') {
|
|
120
99
|
return processAutoGeneratedItem(item);
|
|
@@ -124,32 +103,24 @@ async function processSidebar(
|
|
|
124
103
|
|
|
125
104
|
async function processItems(
|
|
126
105
|
items: NormalizedSidebarItem[],
|
|
127
|
-
): Promise<
|
|
106
|
+
): Promise<ProcessedSidebarItem[]> {
|
|
128
107
|
return (await Promise.all(items.map(processItem))).flat();
|
|
129
108
|
}
|
|
130
109
|
|
|
131
110
|
const processedSidebar = await processItems(unprocessedSidebar);
|
|
132
|
-
|
|
133
|
-
const fixSidebarItemInconsistencies = (item: SidebarItem): SidebarItem => {
|
|
134
|
-
// A non-collapsible category can't be collapsed!
|
|
135
|
-
if (item.type === 'category' && !item.collapsible && item.collapsed) {
|
|
136
|
-
return {
|
|
137
|
-
...item,
|
|
138
|
-
collapsed: false,
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
return item;
|
|
142
|
-
};
|
|
143
|
-
return transformSidebarItems(processedSidebar, fixSidebarItemInconsistencies);
|
|
111
|
+
return processedSidebar;
|
|
144
112
|
}
|
|
145
113
|
|
|
146
114
|
export async function processSidebars(
|
|
147
115
|
unprocessedSidebars: NormalizedSidebars,
|
|
116
|
+
categoriesMetadata: Record<string, CategoryMetadataFile>,
|
|
148
117
|
params: SidebarProcessorParams,
|
|
149
|
-
): Promise<
|
|
150
|
-
|
|
151
|
-
mapValues(unprocessedSidebars, (unprocessedSidebar) =>
|
|
152
|
-
processSidebar(unprocessedSidebar, params),
|
|
118
|
+
): Promise<ProcessedSidebars> {
|
|
119
|
+
const processedSidebars = await combinePromises(
|
|
120
|
+
_.mapValues(unprocessedSidebars, (unprocessedSidebar) =>
|
|
121
|
+
processSidebar(unprocessedSidebar, categoriesMetadata, params),
|
|
153
122
|
),
|
|
154
123
|
);
|
|
124
|
+
validateSidebars(processedSidebars);
|
|
125
|
+
return processedSidebars;
|
|
155
126
|
}
|
package/src/sidebars/types.ts
CHANGED
|
@@ -12,6 +12,7 @@ import type {
|
|
|
12
12
|
SidebarOptions,
|
|
13
13
|
CategoryIndexMatcher,
|
|
14
14
|
} from '@docusaurus/plugin-content-docs';
|
|
15
|
+
import type {Slugger} from '@docusaurus/utils';
|
|
15
16
|
|
|
16
17
|
// Makes all properties visible when hovering over the type
|
|
17
18
|
type Expand<T extends Record<string, unknown>> = {[P in keyof T]: T[P]};
|
|
@@ -27,6 +28,12 @@ export type SidebarItemDoc = SidebarItemBase & {
|
|
|
27
28
|
id: string;
|
|
28
29
|
};
|
|
29
30
|
|
|
31
|
+
export type SidebarItemHtml = SidebarItemBase & {
|
|
32
|
+
type: 'html';
|
|
33
|
+
value: string;
|
|
34
|
+
defaultStyle?: boolean;
|
|
35
|
+
};
|
|
36
|
+
|
|
30
37
|
export type SidebarItemLink = SidebarItemBase & {
|
|
31
38
|
type: 'link';
|
|
32
39
|
href: string;
|
|
@@ -76,17 +83,18 @@ export type SidebarItemCategoryLink =
|
|
|
76
83
|
// The user-given configuration in sidebars.js, before normalization
|
|
77
84
|
export type SidebarItemCategoryConfig = Expand<
|
|
78
85
|
Optional<SidebarItemCategoryBase, 'collapsed' | 'collapsible'> & {
|
|
79
|
-
items: SidebarItemConfig[];
|
|
86
|
+
items: SidebarCategoriesShorthand | SidebarItemConfig[];
|
|
80
87
|
link?: SidebarItemCategoryLinkConfig;
|
|
81
88
|
}
|
|
82
89
|
>;
|
|
83
90
|
|
|
84
91
|
export type SidebarCategoriesShorthand = {
|
|
85
|
-
[sidebarCategory: string]: SidebarItemConfig[];
|
|
92
|
+
[sidebarCategory: string]: SidebarCategoriesShorthand | SidebarItemConfig[];
|
|
86
93
|
};
|
|
87
94
|
|
|
88
95
|
export type SidebarItemConfig =
|
|
89
96
|
| SidebarItemDoc
|
|
97
|
+
| SidebarItemHtml
|
|
90
98
|
| SidebarItemLink
|
|
91
99
|
| SidebarItemAutogenerated
|
|
92
100
|
| SidebarItemCategoryConfig
|
|
@@ -100,14 +108,15 @@ export type SidebarsConfig = {
|
|
|
100
108
|
|
|
101
109
|
// Normalized but still has 'autogenerated', which will be handled in processing
|
|
102
110
|
export type NormalizedSidebarItemCategory = Expand<
|
|
103
|
-
SidebarItemCategoryBase & {
|
|
111
|
+
Optional<SidebarItemCategoryBase, 'collapsed' | 'collapsible'> & {
|
|
104
112
|
items: NormalizedSidebarItem[];
|
|
105
|
-
link?:
|
|
113
|
+
link?: SidebarItemCategoryLinkConfig;
|
|
106
114
|
}
|
|
107
115
|
>;
|
|
108
116
|
|
|
109
117
|
export type NormalizedSidebarItem =
|
|
110
118
|
| SidebarItemDoc
|
|
119
|
+
| SidebarItemHtml
|
|
111
120
|
| SidebarItemLink
|
|
112
121
|
| NormalizedSidebarItemCategory
|
|
113
122
|
| SidebarItemAutogenerated;
|
|
@@ -117,6 +126,22 @@ export type NormalizedSidebars = {
|
|
|
117
126
|
[sidebarId: string]: NormalizedSidebar;
|
|
118
127
|
};
|
|
119
128
|
|
|
129
|
+
export type ProcessedSidebarItemCategory = Expand<
|
|
130
|
+
Optional<SidebarItemCategoryBase, 'collapsed' | 'collapsible'> & {
|
|
131
|
+
items: ProcessedSidebarItem[];
|
|
132
|
+
link?: SidebarItemCategoryLinkConfig;
|
|
133
|
+
}
|
|
134
|
+
>;
|
|
135
|
+
export type ProcessedSidebarItem =
|
|
136
|
+
| SidebarItemDoc
|
|
137
|
+
| SidebarItemHtml
|
|
138
|
+
| SidebarItemLink
|
|
139
|
+
| ProcessedSidebarItemCategory;
|
|
140
|
+
export type ProcessedSidebar = ProcessedSidebarItem[];
|
|
141
|
+
export type ProcessedSidebars = {
|
|
142
|
+
[sidebarId: string]: ProcessedSidebar;
|
|
143
|
+
};
|
|
144
|
+
|
|
120
145
|
export type SidebarItemCategory = Expand<
|
|
121
146
|
SidebarItemCategoryBase & {
|
|
122
147
|
items: SidebarItem[];
|
|
@@ -131,6 +156,7 @@ export type SidebarItemCategoryWithGeneratedIndex =
|
|
|
131
156
|
|
|
132
157
|
export type SidebarItem =
|
|
133
158
|
| SidebarItemDoc
|
|
159
|
+
| SidebarItemHtml
|
|
134
160
|
| SidebarItemLink
|
|
135
161
|
| SidebarItemCategory;
|
|
136
162
|
|
|
@@ -158,12 +184,21 @@ export type PropSidebarItemLink = SidebarItemLink & {
|
|
|
158
184
|
docId?: string;
|
|
159
185
|
};
|
|
160
186
|
|
|
161
|
-
export type
|
|
187
|
+
export type PropSidebarItemHtml = SidebarItemHtml;
|
|
188
|
+
|
|
189
|
+
export type PropSidebarItem =
|
|
190
|
+
| PropSidebarItemLink
|
|
191
|
+
| PropSidebarItemCategory
|
|
192
|
+
| PropSidebarItemHtml;
|
|
162
193
|
export type PropSidebar = PropSidebarItem[];
|
|
163
194
|
export type PropSidebars = {
|
|
164
195
|
[sidebarId: string]: PropSidebar;
|
|
165
196
|
};
|
|
166
197
|
|
|
198
|
+
export type PropSidebarBreadcrumbsItem =
|
|
199
|
+
| PropSidebarItemLink
|
|
200
|
+
| PropSidebarItemCategory;
|
|
201
|
+
|
|
167
202
|
export type PropVersionDoc = {
|
|
168
203
|
id: string;
|
|
169
204
|
title: string;
|
|
@@ -174,6 +209,20 @@ export type PropVersionDocs = {
|
|
|
174
209
|
[docId: string]: PropVersionDoc;
|
|
175
210
|
};
|
|
176
211
|
|
|
212
|
+
export type CategoryMetadataFile = {
|
|
213
|
+
label?: string;
|
|
214
|
+
position?: number;
|
|
215
|
+
collapsed?: boolean;
|
|
216
|
+
collapsible?: boolean;
|
|
217
|
+
className?: string;
|
|
218
|
+
link?: SidebarItemCategoryLinkConfig | null;
|
|
219
|
+
|
|
220
|
+
// TODO should we allow "items" here? how would this work? would an
|
|
221
|
+
// "autogenerated" type be allowed?
|
|
222
|
+
// This mkdocs plugin do something like that: https://github.com/lukasgeiter/mkdocs-awesome-pages-plugin/
|
|
223
|
+
// cf comment: https://github.com/facebook/docusaurus/issues/3464#issuecomment-784765199
|
|
224
|
+
};
|
|
225
|
+
|
|
177
226
|
// Reduce API surface for options.sidebarItemsGenerator
|
|
178
227
|
// The user-provided generator fn should receive only a subset of metadata
|
|
179
228
|
// A change to any of these metadata can be considered as a breaking change
|
|
@@ -197,19 +246,28 @@ export type SidebarItemsGeneratorArgs = {
|
|
|
197
246
|
docs: SidebarItemsGeneratorDoc[];
|
|
198
247
|
numberPrefixParser: NumberPrefixParser;
|
|
199
248
|
isCategoryIndex: CategoryIndexMatcher;
|
|
249
|
+
categoriesMetadata: Record<string, CategoryMetadataFile>;
|
|
200
250
|
options: SidebarOptions;
|
|
201
251
|
};
|
|
202
252
|
export type SidebarItemsGenerator = (
|
|
203
253
|
generatorArgs: SidebarItemsGeneratorArgs,
|
|
204
|
-
) =>
|
|
205
|
-
Promise<SidebarItem[]>;
|
|
206
|
-
// Promise<SidebarItemConfig[]>;
|
|
254
|
+
) => Promise<NormalizedSidebar>;
|
|
207
255
|
|
|
208
|
-
// Also inject the default generator to conveniently wrap/enhance/sort the
|
|
256
|
+
// Also inject the default generator to conveniently wrap/enhance/sort the
|
|
257
|
+
// default sidebar gen logic
|
|
209
258
|
// see https://github.com/facebook/docusaurus/issues/4640#issuecomment-822292320
|
|
210
259
|
export type SidebarItemsGeneratorOptionArgs = {
|
|
211
260
|
defaultSidebarItemsGenerator: SidebarItemsGenerator;
|
|
212
261
|
} & SidebarItemsGeneratorArgs;
|
|
213
262
|
export type SidebarItemsGeneratorOption = (
|
|
214
263
|
generatorArgs: SidebarItemsGeneratorOptionArgs,
|
|
215
|
-
) => Promise<
|
|
264
|
+
) => Promise<NormalizedSidebarItem[]>;
|
|
265
|
+
|
|
266
|
+
export type SidebarProcessorParams = {
|
|
267
|
+
sidebarItemsGenerator: SidebarItemsGeneratorOption;
|
|
268
|
+
numberPrefixParser: NumberPrefixParser;
|
|
269
|
+
docs: DocMetadataBase[];
|
|
270
|
+
version: VersionMetadata;
|
|
271
|
+
categoryLabelSlugger: Slugger;
|
|
272
|
+
sidebarOptions: SidebarOptions;
|
|
273
|
+
};
|