@docusaurus/plugin-content-docs 0.0.0-4547 → 0.0.0-4551
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.js +2 -1
- package/lib/client/index.d.ts +13 -1
- package/lib/client/index.js +66 -1
- package/lib/{server/index.d.ts → server-export.d.ts} +2 -2
- package/lib/{server/index.js → server-export.js} +7 -4
- package/lib/sidebars/generator.js +6 -7
- package/lib/sidebars/index.d.ts +3 -6
- package/lib/sidebars/index.js +8 -18
- package/lib/sidebars/normalization.d.ts +2 -3
- package/lib/sidebars/normalization.js +14 -32
- package/lib/sidebars/postProcessor.d.ts +8 -0
- package/lib/sidebars/postProcessor.js +71 -0
- package/lib/sidebars/processor.d.ts +2 -14
- package/lib/sidebars/processor.js +17 -55
- package/lib/sidebars/types.d.ts +24 -6
- package/lib/sidebars/utils.js +0 -1
- package/lib/sidebars/validation.d.ts +2 -2
- package/lib/sidebars/validation.js +12 -27
- package/lib/types.d.ts +2 -6
- package/package.json +10 -10
- package/src/cli.ts +3 -2
- package/src/client/index.ts +97 -1
- package/src/{server/index.ts → server-export.ts} +7 -2
- package/src/sidebars/README.md +9 -0
- package/src/sidebars/generator.ts +25 -22
- package/src/sidebars/index.ts +15 -31
- package/src/sidebars/normalization.ts +18 -46
- package/src/sidebars/postProcessor.ts +94 -0
- package/src/sidebars/processor.ts +26 -90
- package/src/sidebars/types.ts +32 -8
- package/src/sidebars/utils.ts +0 -1
- package/src/sidebars/validation.ts +38 -50
- package/src/types.ts +2 -10
- package/lib/client/globalDataHooks.d.ts +0 -19
- package/lib/client/globalDataHooks.js +0 -77
- package/src/client/globalDataHooks.ts +0 -108
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
9
|
exports.validateCategoryMetadataFile = exports.validateSidebars = void 0;
|
|
10
10
|
const utils_validation_1 = require("@docusaurus/utils-validation");
|
|
11
|
-
const utils_1 = require("./utils");
|
|
12
11
|
// NOTE: we don't add any default values during validation on purpose!
|
|
13
12
|
// Config types are exposed to users for typechecking and we use the same type
|
|
14
13
|
// in normalization
|
|
@@ -31,7 +30,7 @@ const sidebarItemDocSchema = sidebarItemBaseSchema.append({
|
|
|
31
30
|
const sidebarItemHtmlSchema = sidebarItemBaseSchema.append({
|
|
32
31
|
type: 'html',
|
|
33
32
|
value: utils_validation_1.Joi.string().required(),
|
|
34
|
-
defaultStyle: utils_validation_1.Joi.boolean()
|
|
33
|
+
defaultStyle: utils_validation_1.Joi.boolean(),
|
|
35
34
|
});
|
|
36
35
|
const sidebarItemLinkSchema = sidebarItemBaseSchema.append({
|
|
37
36
|
type: 'link',
|
|
@@ -65,23 +64,23 @@ const sidebarItemCategoryLinkSchema = utils_validation_1.Joi.object()
|
|
|
65
64
|
}),
|
|
66
65
|
},
|
|
67
66
|
{
|
|
68
|
-
is: utils_validation_1.Joi.
|
|
67
|
+
is: utils_validation_1.Joi.required(),
|
|
69
68
|
then: utils_validation_1.Joi.forbidden().messages({
|
|
70
69
|
'any.unknown': 'Unknown sidebar category link type "{.type}".',
|
|
71
70
|
}),
|
|
72
71
|
},
|
|
73
72
|
],
|
|
74
|
-
})
|
|
75
|
-
.id('sidebarCategoryLinkSchema');
|
|
73
|
+
});
|
|
76
74
|
const sidebarItemCategorySchema = sidebarItemBaseSchema.append({
|
|
77
75
|
type: 'category',
|
|
78
76
|
label: utils_validation_1.Joi.string()
|
|
79
77
|
.required()
|
|
80
78
|
.messages({ 'any.unknown': '"label" must be a string' }),
|
|
81
|
-
// TODO: Joi doesn't allow mutual recursion. See https://github.com/sideway/joi/issues/2611
|
|
82
79
|
items: utils_validation_1.Joi.array()
|
|
83
80
|
.required()
|
|
84
81
|
.messages({ 'any.unknown': '"items" must be an array' }),
|
|
82
|
+
// TODO: Joi doesn't allow mutual recursion. See https://github.com/sideway/joi/issues/2611
|
|
83
|
+
// .items(Joi.link('#sidebarItemSchema')),
|
|
85
84
|
link: sidebarItemCategoryLinkSchema,
|
|
86
85
|
collapsed: utils_validation_1.Joi.boolean().messages({
|
|
87
86
|
'any.unknown': '"collapsed" must be a boolean',
|
|
@@ -90,8 +89,7 @@ const sidebarItemCategorySchema = sidebarItemBaseSchema.append({
|
|
|
90
89
|
'any.unknown': '"collapsible" must be a boolean',
|
|
91
90
|
}),
|
|
92
91
|
});
|
|
93
|
-
const sidebarItemSchema = utils_validation_1.Joi.object()
|
|
94
|
-
.when('.type', {
|
|
92
|
+
const sidebarItemSchema = utils_validation_1.Joi.object().when('.type', {
|
|
95
93
|
switch: [
|
|
96
94
|
{ is: 'link', then: sidebarItemLinkSchema },
|
|
97
95
|
{
|
|
@@ -108,33 +106,20 @@ const sidebarItemSchema = utils_validation_1.Joi.object()
|
|
|
108
106
|
}),
|
|
109
107
|
},
|
|
110
108
|
],
|
|
111
|
-
})
|
|
112
|
-
|
|
109
|
+
});
|
|
110
|
+
// .id('sidebarItemSchema');
|
|
113
111
|
function validateSidebarItem(item) {
|
|
114
|
-
if (typeof item === 'string') {
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
112
|
// TODO: remove once with proper Joi support
|
|
118
113
|
// Because we can't use Joi to validate nested items (see above), we do it
|
|
119
114
|
// manually
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
else {
|
|
124
|
-
utils_validation_1.Joi.assert(item, sidebarItemSchema);
|
|
125
|
-
if (item.type === 'category') {
|
|
126
|
-
item.items.forEach(validateSidebarItem);
|
|
127
|
-
}
|
|
115
|
+
utils_validation_1.Joi.assert(item, sidebarItemSchema);
|
|
116
|
+
if (item.type === 'category') {
|
|
117
|
+
item.items.forEach(validateSidebarItem);
|
|
128
118
|
}
|
|
129
119
|
}
|
|
130
120
|
function validateSidebars(sidebars) {
|
|
131
121
|
Object.values(sidebars).forEach((sidebar) => {
|
|
132
|
-
|
|
133
|
-
sidebar.forEach(validateSidebarItem);
|
|
134
|
-
}
|
|
135
|
-
else {
|
|
136
|
-
validateSidebarItem(sidebar);
|
|
137
|
-
}
|
|
122
|
+
sidebar.forEach(validateSidebarItem);
|
|
138
123
|
});
|
|
139
124
|
}
|
|
140
125
|
exports.validateSidebars = validateSidebars;
|
package/lib/types.d.ts
CHANGED
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
import type { Sidebars } from './sidebars/types';
|
|
8
|
-
import type { Tag, FrontMatterTag
|
|
8
|
+
import type { Tag, FrontMatterTag } from '@docusaurus/utils';
|
|
9
9
|
import type { BrokenMarkdownLink as IBrokenMarkdownLink, ContentPaths } from '@docusaurus/utils/lib/markdownLinks';
|
|
10
|
-
import type { VersionBanner
|
|
10
|
+
import type { VersionBanner } from '@docusaurus/plugin-content-docs';
|
|
11
11
|
export declare type DocFile = {
|
|
12
12
|
contentPath: string;
|
|
13
13
|
filePath: string;
|
|
@@ -29,10 +29,6 @@ export declare type VersionMetadata = ContentPaths & {
|
|
|
29
29
|
sidebarFilePath: string | false | undefined;
|
|
30
30
|
routePriority: number | undefined;
|
|
31
31
|
};
|
|
32
|
-
export declare type NormalizeSidebarsParams = SidebarOptions & {
|
|
33
|
-
version: VersionMetadata;
|
|
34
|
-
categoryLabelSlugger: Slugger;
|
|
35
|
-
};
|
|
36
32
|
export declare type LastUpdateData = {
|
|
37
33
|
lastUpdatedAt?: number;
|
|
38
34
|
formattedLastUpdatedAt?: string;
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@docusaurus/plugin-content-docs",
|
|
3
|
-
"version": "0.0.0-
|
|
3
|
+
"version": "0.0.0-4551",
|
|
4
4
|
"description": "Docs plugin for Docusaurus.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"exports": {
|
|
7
7
|
"./client": "./lib/client/index.js",
|
|
8
|
-
"./server": "./lib/server
|
|
8
|
+
"./server": "./lib/server-export.js",
|
|
9
9
|
".": "./lib/index.js"
|
|
10
10
|
},
|
|
11
11
|
"types": "src/plugin-content-docs.d.ts",
|
|
@@ -23,11 +23,11 @@
|
|
|
23
23
|
},
|
|
24
24
|
"license": "MIT",
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@docusaurus/core": "0.0.0-
|
|
27
|
-
"@docusaurus/logger": "0.0.0-
|
|
28
|
-
"@docusaurus/mdx-loader": "0.0.0-
|
|
29
|
-
"@docusaurus/utils": "0.0.0-
|
|
30
|
-
"@docusaurus/utils-validation": "0.0.0-
|
|
26
|
+
"@docusaurus/core": "0.0.0-4551",
|
|
27
|
+
"@docusaurus/logger": "0.0.0-4551",
|
|
28
|
+
"@docusaurus/mdx-loader": "0.0.0-4551",
|
|
29
|
+
"@docusaurus/utils": "0.0.0-4551",
|
|
30
|
+
"@docusaurus/utils-validation": "0.0.0-4551",
|
|
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-
|
|
44
|
-
"@docusaurus/types": "0.0.0-
|
|
43
|
+
"@docusaurus/module-type-aliases": "0.0.0-4551",
|
|
44
|
+
"@docusaurus/types": "0.0.0-4551",
|
|
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": "
|
|
60
|
+
"gitHead": "a948920b43d31d651edbe5d642ccd9fb88b09ecd"
|
|
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 {
|
|
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
|
-
|
|
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)
|
package/src/client/index.ts
CHANGED
|
@@ -5,4 +5,100 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
import {useLocation} from '@docusaurus/router';
|
|
9
|
+
import useGlobalData, {usePluginData} from '@docusaurus/useGlobalData';
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
getActivePlugin,
|
|
13
|
+
getLatestVersion,
|
|
14
|
+
getActiveVersion,
|
|
15
|
+
getActiveDocContext,
|
|
16
|
+
getDocVersionSuggestions,
|
|
17
|
+
} from './docsClientUtils';
|
|
18
|
+
import type {
|
|
19
|
+
GlobalPluginData,
|
|
20
|
+
GlobalVersion,
|
|
21
|
+
ActivePlugin,
|
|
22
|
+
ActiveDocContext,
|
|
23
|
+
DocVersionSuggestions,
|
|
24
|
+
GetActivePluginOptions,
|
|
25
|
+
} from '@docusaurus/plugin-content-docs/client';
|
|
26
|
+
|
|
27
|
+
// Important to use a constant object to avoid React useEffect executions etc.
|
|
28
|
+
// see https://github.com/facebook/docusaurus/issues/5089
|
|
29
|
+
const StableEmptyObject = {};
|
|
30
|
+
|
|
31
|
+
// Not using useAllPluginInstancesData() because in blog-only mode, docs hooks
|
|
32
|
+
// are still used by the theme. We need a fail-safe fallback when the docs
|
|
33
|
+
// plugin is not in use
|
|
34
|
+
export const useAllDocsData = (): Record<string, GlobalPluginData> =>
|
|
35
|
+
useGlobalData()['docusaurus-plugin-content-docs'] ?? StableEmptyObject;
|
|
36
|
+
|
|
37
|
+
export const useDocsData = (pluginId: string | undefined): GlobalPluginData =>
|
|
38
|
+
usePluginData('docusaurus-plugin-content-docs', pluginId) as GlobalPluginData;
|
|
39
|
+
|
|
40
|
+
// TODO this feature should be provided by docusaurus core
|
|
41
|
+
export const useActivePlugin = (
|
|
42
|
+
options: GetActivePluginOptions = {},
|
|
43
|
+
): ActivePlugin | undefined => {
|
|
44
|
+
const data = useAllDocsData();
|
|
45
|
+
const {pathname} = useLocation();
|
|
46
|
+
return getActivePlugin(data, pathname, options);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const useActivePluginAndVersion = (
|
|
50
|
+
options: GetActivePluginOptions = {},
|
|
51
|
+
):
|
|
52
|
+
| undefined
|
|
53
|
+
| {activePlugin: ActivePlugin; activeVersion: GlobalVersion | undefined} => {
|
|
54
|
+
const activePlugin = useActivePlugin(options);
|
|
55
|
+
const {pathname} = useLocation();
|
|
56
|
+
if (activePlugin) {
|
|
57
|
+
const activeVersion = getActiveVersion(activePlugin.pluginData, pathname);
|
|
58
|
+
return {
|
|
59
|
+
activePlugin,
|
|
60
|
+
activeVersion,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
return undefined;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
// versions are returned ordered (most recent first)
|
|
67
|
+
export const useVersions = (pluginId: string | undefined): GlobalVersion[] => {
|
|
68
|
+
const data = useDocsData(pluginId);
|
|
69
|
+
return data.versions;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export const useLatestVersion = (
|
|
73
|
+
pluginId: string | undefined,
|
|
74
|
+
): GlobalVersion => {
|
|
75
|
+
const data = useDocsData(pluginId);
|
|
76
|
+
return getLatestVersion(data);
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
// Note: return undefined on doc-unrelated pages,
|
|
80
|
+
// because there's no version currently considered as active
|
|
81
|
+
export const useActiveVersion = (
|
|
82
|
+
pluginId: string | undefined,
|
|
83
|
+
): GlobalVersion | undefined => {
|
|
84
|
+
const data = useDocsData(pluginId);
|
|
85
|
+
const {pathname} = useLocation();
|
|
86
|
+
return getActiveVersion(data, pathname);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export const useActiveDocContext = (
|
|
90
|
+
pluginId: string | undefined,
|
|
91
|
+
): ActiveDocContext => {
|
|
92
|
+
const data = useDocsData(pluginId);
|
|
93
|
+
const {pathname} = useLocation();
|
|
94
|
+
return getActiveDocContext(data, pathname);
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
// Useful to say "hey, you are not on the latest docs version, please switch"
|
|
98
|
+
export const useDocVersionSuggestions = (
|
|
99
|
+
pluginId: string | undefined,
|
|
100
|
+
): DocVersionSuggestions => {
|
|
101
|
+
const data = useDocsData(pluginId);
|
|
102
|
+
const {pathname} = useLocation();
|
|
103
|
+
return getDocVersionSuggestions(data, pathname);
|
|
104
|
+
};
|
|
@@ -6,7 +6,12 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
// APIs available to Node.js
|
|
9
|
-
export
|
|
9
|
+
export {
|
|
10
|
+
CURRENT_VERSION_NAME,
|
|
11
|
+
VERSIONED_DOCS_DIR,
|
|
12
|
+
VERSIONED_SIDEBARS_DIR,
|
|
13
|
+
VERSIONS_JSON_FILE,
|
|
14
|
+
} from './constants';
|
|
10
15
|
|
|
11
16
|
export {
|
|
12
17
|
filterVersions,
|
|
@@ -16,4 +21,4 @@ export {
|
|
|
16
21
|
getVersionsFilePath,
|
|
17
22
|
readVersionsFile,
|
|
18
23
|
readVersionNames,
|
|
19
|
-
} from '
|
|
24
|
+
} from './versions';
|
|
@@ -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
|
-
|
|
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(
|
|
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<
|
|
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)
|
|
164
|
-
|
|
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
|
-
})
|
|
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:
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
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
|
-
|
|
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<
|
|
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(
|
|
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)};
|
package/src/sidebars/index.ts
CHANGED
|
@@ -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,
|
|
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
|
|
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
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:
|
|
99
|
+
options: SidebarProcessorParams,
|
|
115
100
|
): Promise<Sidebars> {
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
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
|
-
|
|
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
|
|
76
|
-
normalizeItem(subItem
|
|
48
|
+
return normalizeCategoriesShorthand(item).flatMap((subItem) =>
|
|
49
|
+
normalizeItem(subItem),
|
|
77
50
|
);
|
|
78
51
|
}
|
|
79
52
|
if (item.type === 'category') {
|
|
80
|
-
|
|
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
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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
|
|
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,
|
|
84
|
+
return mapValues(sidebars, normalizeSidebar);
|
|
113
85
|
}
|