@docusaurus/plugin-content-docs 2.0.0-beta.16 → 2.0.0-beta.19
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/categoryGeneratedIndex.d.ts +1 -1
- package/lib/categoryGeneratedIndex.js +5 -7
- package/lib/cli.d.ts +3 -2
- package/lib/cli.js +49 -41
- package/lib/client/docsClientUtils.d.ts +8 -5
- package/lib/client/docsClientUtils.js +13 -15
- package/lib/client/index.d.ts +12 -9
- package/lib/client/index.js +30 -33
- package/lib/constants.d.ts +4 -0
- package/lib/constants.js +4 -1
- package/lib/docs.d.ts +8 -15
- package/lib/docs.js +34 -39
- package/lib/{docFrontMatter.d.ts → frontMatter.d.ts} +4 -2
- package/lib/{docFrontMatter.js → frontMatter.js} +3 -0
- package/lib/globalData.d.ts +3 -7
- package/lib/globalData.js +9 -13
- package/lib/index.d.ts +1 -2
- package/lib/index.js +33 -26
- package/lib/lastUpdate.d.ts +4 -6
- package/lib/lastUpdate.js +14 -5
- package/lib/markdown/index.js +1 -1
- package/lib/markdown/linkify.js +5 -2
- package/lib/numberPrefix.js +16 -22
- package/lib/options.d.ts +3 -5
- package/lib/options.js +6 -5
- package/lib/props.d.ts +3 -3
- package/lib/props.js +10 -10
- package/lib/routes.d.ts +5 -4
- package/lib/routes.js +10 -24
- package/lib/server-export.d.ts +2 -1
- package/lib/server-export.js +3 -4
- package/lib/sidebars/generator.js +63 -44
- package/lib/sidebars/index.js +20 -16
- package/lib/sidebars/normalization.js +3 -3
- package/lib/sidebars/postProcessor.js +18 -25
- package/lib/sidebars/processor.d.ts +3 -1
- package/lib/sidebars/processor.js +17 -6
- package/lib/sidebars/types.d.ts +31 -19
- package/lib/sidebars/utils.d.ts +17 -6
- package/lib/sidebars/utils.js +27 -37
- package/lib/sidebars/validation.d.ts +3 -1
- package/lib/sidebars/validation.js +1 -0
- package/lib/slug.d.ts +1 -2
- package/lib/slug.js +4 -5
- package/lib/tags.d.ts +2 -1
- package/lib/tags.js +2 -2
- package/lib/translations.d.ts +3 -3
- package/lib/translations.js +28 -81
- package/lib/types.d.ts +10 -95
- package/lib/versions/files.d.ts +44 -0
- package/lib/versions/files.js +142 -0
- package/lib/versions/index.d.ts +36 -0
- package/lib/versions/index.js +155 -0
- package/lib/versions/validation.d.ts +17 -0
- package/lib/versions/validation.js +71 -0
- package/package.json +14 -12
- package/src/categoryGeneratedIndex.ts +10 -9
- package/src/cli.ts +64 -69
- package/src/client/docsClientUtils.ts +14 -16
- package/src/client/index.ts +42 -43
- package/src/constants.ts +4 -2
- package/src/deps.d.ts +1 -1
- package/src/docs.ts +48 -51
- package/src/{docFrontMatter.ts → frontMatter.ts} +9 -6
- package/src/globalData.ts +15 -16
- package/src/index.ts +45 -40
- package/src/lastUpdate.ts +20 -8
- package/src/markdown/index.ts +1 -3
- package/src/markdown/linkify.ts +6 -3
- package/src/numberPrefix.ts +18 -28
- package/src/options.ts +6 -8
- package/src/plugin-content-docs.d.ts +457 -116
- package/src/props.ts +12 -9
- package/src/routes.ts +13 -39
- package/src/server-export.ts +1 -3
- package/src/sidebars/generator.ts +88 -59
- package/src/sidebars/index.ts +20 -15
- package/src/sidebars/normalization.ts +1 -1
- package/src/sidebars/postProcessor.ts +6 -11
- package/src/sidebars/processor.ts +27 -14
- package/src/sidebars/types.ts +25 -23
- package/src/sidebars/utils.ts +45 -46
- package/src/sidebars/validation.ts +4 -3
- package/src/slug.ts +7 -6
- package/src/tags.ts +3 -2
- package/src/translations.ts +32 -84
- package/src/types.ts +15 -107
- package/src/versions/files.ts +220 -0
- package/src/versions/index.ts +247 -0
- package/src/versions/validation.ts +113 -0
- package/lib/versions.d.ts +0 -41
- package/lib/versions.js +0 -329
- package/src/versions.ts +0 -606
package/src/props.ts
CHANGED
|
@@ -5,13 +5,12 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import type {
|
|
8
|
+
import type {VersionTag} from './types';
|
|
9
9
|
import type {
|
|
10
10
|
SidebarItemDoc,
|
|
11
11
|
SidebarItem,
|
|
12
12
|
SidebarItemCategory,
|
|
13
13
|
SidebarItemCategoryLink,
|
|
14
|
-
PropVersionDocs,
|
|
15
14
|
} from './sidebars/types';
|
|
16
15
|
import type {
|
|
17
16
|
PropSidebars,
|
|
@@ -21,6 +20,9 @@ import type {
|
|
|
21
20
|
PropTagDocList,
|
|
22
21
|
PropTagDocListDoc,
|
|
23
22
|
PropSidebarItemLink,
|
|
23
|
+
PropVersionDocs,
|
|
24
|
+
DocMetadata,
|
|
25
|
+
LoadedVersion,
|
|
24
26
|
} from '@docusaurus/plugin-content-docs';
|
|
25
27
|
import _ from 'lodash';
|
|
26
28
|
import {createDocsByIdIndex} from './docs';
|
|
@@ -119,10 +121,10 @@ export function toVersionMetadataProp(
|
|
|
119
121
|
return {
|
|
120
122
|
pluginId,
|
|
121
123
|
version: loadedVersion.versionName,
|
|
122
|
-
label: loadedVersion.
|
|
123
|
-
banner: loadedVersion.
|
|
124
|
-
badge: loadedVersion.
|
|
125
|
-
className: loadedVersion.
|
|
124
|
+
label: loadedVersion.label,
|
|
125
|
+
banner: loadedVersion.banner,
|
|
126
|
+
badge: loadedVersion.badge,
|
|
127
|
+
className: loadedVersion.className,
|
|
126
128
|
isLast: loadedVersion.isLast,
|
|
127
129
|
docsSidebars: toSidebarsProp(loadedVersion),
|
|
128
130
|
docs: toVersionDocsProp(loadedVersion),
|
|
@@ -136,7 +138,7 @@ export function toTagDocListProp({
|
|
|
136
138
|
}: {
|
|
137
139
|
allTagsPath: string;
|
|
138
140
|
tag: VersionTag;
|
|
139
|
-
docs:
|
|
141
|
+
docs: DocMetadata[];
|
|
140
142
|
}): PropTagDocList {
|
|
141
143
|
function toDocListProp(): PropTagDocListDoc[] {
|
|
142
144
|
const list = _.compact(
|
|
@@ -153,9 +155,10 @@ export function toTagDocListProp({
|
|
|
153
155
|
}
|
|
154
156
|
|
|
155
157
|
return {
|
|
156
|
-
|
|
158
|
+
label: tag.label,
|
|
157
159
|
permalink: tag.permalink,
|
|
158
|
-
docs: toDocListProp(),
|
|
159
160
|
allTagsPath,
|
|
161
|
+
count: tag.docIds.length,
|
|
162
|
+
items: toDocListProp(),
|
|
160
163
|
};
|
|
161
164
|
}
|
package/src/routes.ts
CHANGED
|
@@ -7,12 +7,11 @@
|
|
|
7
7
|
|
|
8
8
|
import type {PluginContentLoadedActions, RouteConfig} from '@docusaurus/types';
|
|
9
9
|
import {docuHash, createSlugger} from '@docusaurus/utils';
|
|
10
|
+
import type {FullVersion} from './types';
|
|
10
11
|
import type {
|
|
11
12
|
CategoryGeneratedIndexMetadata,
|
|
12
13
|
DocMetadata,
|
|
13
|
-
|
|
14
|
-
} from './types';
|
|
15
|
-
import type {PropCategoryGeneratedIndex} from '@docusaurus/plugin-content-docs';
|
|
14
|
+
} from '@docusaurus/plugin-content-docs';
|
|
16
15
|
import {toVersionMetadataProp} from './props';
|
|
17
16
|
import logger from '@docusaurus/logger';
|
|
18
17
|
|
|
@@ -22,7 +21,7 @@ export async function createCategoryGeneratedIndexRoutes({
|
|
|
22
21
|
docCategoryGeneratedIndexComponent,
|
|
23
22
|
aliasedSource,
|
|
24
23
|
}: {
|
|
25
|
-
version:
|
|
24
|
+
version: FullVersion;
|
|
26
25
|
actions: PluginContentLoadedActions;
|
|
27
26
|
docCategoryGeneratedIndexComponent: string;
|
|
28
27
|
aliasedSource: (str: string) => string;
|
|
@@ -32,42 +31,19 @@ export async function createCategoryGeneratedIndexRoutes({
|
|
|
32
31
|
async function createCategoryGeneratedIndexRoute(
|
|
33
32
|
categoryGeneratedIndex: CategoryGeneratedIndexMetadata,
|
|
34
33
|
): Promise<RouteConfig> {
|
|
35
|
-
const {
|
|
36
|
-
sidebar,
|
|
37
|
-
title,
|
|
38
|
-
description,
|
|
39
|
-
slug,
|
|
40
|
-
permalink,
|
|
41
|
-
previous,
|
|
42
|
-
next,
|
|
43
|
-
image,
|
|
44
|
-
keywords,
|
|
45
|
-
} = categoryGeneratedIndex;
|
|
34
|
+
const {sidebar, ...prop} = categoryGeneratedIndex;
|
|
46
35
|
|
|
47
36
|
const propFileName = slugs.slug(
|
|
48
|
-
`${version.
|
|
37
|
+
`${version.path}-${categoryGeneratedIndex.sidebar}-category-${categoryGeneratedIndex.title}`,
|
|
49
38
|
);
|
|
50
39
|
|
|
51
|
-
const prop: PropCategoryGeneratedIndex = {
|
|
52
|
-
title,
|
|
53
|
-
description,
|
|
54
|
-
slug,
|
|
55
|
-
permalink,
|
|
56
|
-
image,
|
|
57
|
-
keywords,
|
|
58
|
-
navigation: {
|
|
59
|
-
previous,
|
|
60
|
-
next,
|
|
61
|
-
},
|
|
62
|
-
};
|
|
63
|
-
|
|
64
40
|
const propData = await actions.createData(
|
|
65
41
|
`${docuHash(`category/${propFileName}`)}.json`,
|
|
66
42
|
JSON.stringify(prop, null, 2),
|
|
67
43
|
);
|
|
68
44
|
|
|
69
45
|
return {
|
|
70
|
-
path: permalink,
|
|
46
|
+
path: categoryGeneratedIndex.permalink,
|
|
71
47
|
component: docCategoryGeneratedIndexComponent,
|
|
72
48
|
exact: true,
|
|
73
49
|
modules: {
|
|
@@ -123,7 +99,7 @@ export async function createDocRoutes({
|
|
|
123
99
|
}
|
|
124
100
|
|
|
125
101
|
export async function createVersionRoutes({
|
|
126
|
-
|
|
102
|
+
version,
|
|
127
103
|
actions,
|
|
128
104
|
docItemComponent,
|
|
129
105
|
docLayoutComponent,
|
|
@@ -131,7 +107,7 @@ export async function createVersionRoutes({
|
|
|
131
107
|
pluginId,
|
|
132
108
|
aliasedSource,
|
|
133
109
|
}: {
|
|
134
|
-
|
|
110
|
+
version: FullVersion;
|
|
135
111
|
actions: PluginContentLoadedActions;
|
|
136
112
|
docLayoutComponent: string;
|
|
137
113
|
docItemComponent: string;
|
|
@@ -139,7 +115,7 @@ export async function createVersionRoutes({
|
|
|
139
115
|
pluginId: string;
|
|
140
116
|
aliasedSource: (str: string) => string;
|
|
141
117
|
}): Promise<void> {
|
|
142
|
-
async function doCreateVersionRoutes(
|
|
118
|
+
async function doCreateVersionRoutes(): Promise<void> {
|
|
143
119
|
const versionMetadata = toVersionMetadataProp(pluginId, version);
|
|
144
120
|
const versionMetadataPropPath = await actions.createData(
|
|
145
121
|
`${docuHash(`version-${version.versionName}-metadata-prop`)}.json`,
|
|
@@ -162,12 +138,10 @@ export async function createVersionRoutes({
|
|
|
162
138
|
}
|
|
163
139
|
|
|
164
140
|
actions.addRoute({
|
|
165
|
-
path: version.
|
|
166
|
-
//
|
|
141
|
+
path: version.path,
|
|
142
|
+
// Allow matching /docs/* since this is the wrapping route
|
|
167
143
|
exact: false,
|
|
168
|
-
// main docs component (DocPage)
|
|
169
144
|
component: docLayoutComponent,
|
|
170
|
-
// sub-routes for each doc
|
|
171
145
|
routes: await createVersionSubRoutes(),
|
|
172
146
|
modules: {
|
|
173
147
|
versionMetadata: aliasedSource(versionMetadataPropPath),
|
|
@@ -177,9 +151,9 @@ export async function createVersionRoutes({
|
|
|
177
151
|
}
|
|
178
152
|
|
|
179
153
|
try {
|
|
180
|
-
return await doCreateVersionRoutes(
|
|
154
|
+
return await doCreateVersionRoutes();
|
|
181
155
|
} catch (err) {
|
|
182
|
-
logger.error`Can't create version routes for version name=${
|
|
156
|
+
logger.error`Can't create version routes for version name=${version.versionName}`;
|
|
183
157
|
throw err;
|
|
184
158
|
}
|
|
185
159
|
}
|
package/src/server-export.ts
CHANGED
|
@@ -14,14 +14,12 @@ import type {
|
|
|
14
14
|
SidebarItemCategoryLinkConfig,
|
|
15
15
|
} from './types';
|
|
16
16
|
import _ from 'lodash';
|
|
17
|
-
import {addTrailingSlash
|
|
17
|
+
import {addTrailingSlash} from '@docusaurus/utils';
|
|
18
18
|
import logger from '@docusaurus/logger';
|
|
19
19
|
import path from 'path';
|
|
20
20
|
import {createDocsByIdIndex, toCategoryIndexMatcherParam} from '../docs';
|
|
21
21
|
|
|
22
22
|
const BreadcrumbSeparator = '/';
|
|
23
|
-
// To avoid possible name clashes with a folder of the same name as the ID
|
|
24
|
-
const docIdPrefix = '$doc$/';
|
|
25
23
|
|
|
26
24
|
// Just an alias to the make code more explicit
|
|
27
25
|
function getLocalDocId(docId: string): string {
|
|
@@ -31,16 +29,20 @@ function getLocalDocId(docId: string): string {
|
|
|
31
29
|
export const CategoryMetadataFilenameBase = '_category_';
|
|
32
30
|
export const CategoryMetadataFilenamePattern = '_category_.{json,yml,yaml}';
|
|
33
31
|
|
|
34
|
-
type WithPosition<T> = T & {
|
|
32
|
+
type WithPosition<T> = T & {
|
|
33
|
+
position?: number;
|
|
34
|
+
/** The source is the file/folder name */
|
|
35
|
+
source?: string;
|
|
36
|
+
};
|
|
35
37
|
|
|
36
38
|
/**
|
|
37
39
|
* A representation of the fs structure. For each object entry:
|
|
38
40
|
* If it's a folder, the key is the directory name, and value is the directory
|
|
39
|
-
* content; If it's a doc file, the key is the doc
|
|
40
|
-
*
|
|
41
|
+
* content; If it's a doc file, the key is the doc's source file name, and value
|
|
42
|
+
* is the doc ID
|
|
41
43
|
*/
|
|
42
44
|
type Dir = {
|
|
43
|
-
[item: string]: Dir |
|
|
45
|
+
[item: string]: Dir | string;
|
|
44
46
|
};
|
|
45
47
|
|
|
46
48
|
// Comment for this feature: https://github.com/facebook/docusaurus/issues/3464#issuecomment-818670449
|
|
@@ -58,9 +60,9 @@ export const DefaultSidebarItemsGenerator: SidebarItemsGenerator = async ({
|
|
|
58
60
|
const doc = findDoc(docId);
|
|
59
61
|
if (!doc) {
|
|
60
62
|
throw new Error(
|
|
61
|
-
`Can't find any doc with
|
|
62
|
-
|
|
63
|
-
|
|
63
|
+
`Can't find any doc with ID ${docId}.
|
|
64
|
+
Available doc IDs:
|
|
65
|
+
- ${Object.keys(docsById).join('\n- ')}`,
|
|
64
66
|
);
|
|
65
67
|
}
|
|
66
68
|
return doc;
|
|
@@ -74,9 +76,9 @@ export const DefaultSidebarItemsGenerator: SidebarItemsGenerator = async ({
|
|
|
74
76
|
return (
|
|
75
77
|
// Doc at the root of the autogenerated sidebar dir
|
|
76
78
|
doc.sourceDirName === autogenDir ||
|
|
77
|
-
//
|
|
79
|
+
// Autogen dir is . and doc is in subfolder
|
|
78
80
|
autogenDir === '.' ||
|
|
79
|
-
//
|
|
81
|
+
// Autogen dir is not . and doc is in subfolder
|
|
80
82
|
// "api/myDoc" startsWith "api/" (note "api2/myDoc" is not included)
|
|
81
83
|
doc.sourceDirName.startsWith(addTrailingSlash(autogenDir))
|
|
82
84
|
);
|
|
@@ -108,14 +110,16 @@ export const DefaultSidebarItemsGenerator: SidebarItemsGenerator = async ({
|
|
|
108
110
|
const treeRoot: Dir = {};
|
|
109
111
|
docs.forEach((doc) => {
|
|
110
112
|
const breadcrumb = getRelativeBreadcrumb(doc);
|
|
111
|
-
|
|
113
|
+
// We walk down the file's path to generate the fs structure
|
|
114
|
+
let currentDir = treeRoot;
|
|
112
115
|
breadcrumb.forEach((dir) => {
|
|
113
116
|
if (typeof currentDir[dir] === 'undefined') {
|
|
114
117
|
currentDir[dir] = {}; // Create new folder.
|
|
115
118
|
}
|
|
116
|
-
currentDir = currentDir[dir]
|
|
119
|
+
currentDir = currentDir[dir] as Dir; // Go into the subdirectory.
|
|
117
120
|
});
|
|
118
|
-
|
|
121
|
+
// We've walked through the path. Register the file in this directory.
|
|
122
|
+
currentDir[path.basename(doc.source)] = doc.id;
|
|
119
123
|
});
|
|
120
124
|
return treeRoot;
|
|
121
125
|
}
|
|
@@ -126,8 +130,12 @@ export const DefaultSidebarItemsGenerator: SidebarItemsGenerator = async ({
|
|
|
126
130
|
*/
|
|
127
131
|
function generateSidebar(
|
|
128
132
|
fsModel: Dir,
|
|
129
|
-
):
|
|
130
|
-
function createDocItem(
|
|
133
|
+
): WithPosition<NormalizedSidebarItem>[] {
|
|
134
|
+
function createDocItem(
|
|
135
|
+
id: string,
|
|
136
|
+
fullPath: string,
|
|
137
|
+
fileName: string,
|
|
138
|
+
): WithPosition<SidebarItemDoc> {
|
|
131
139
|
const {
|
|
132
140
|
sidebarPosition: position,
|
|
133
141
|
frontMatter: {sidebar_label: label, sidebar_class_name: className},
|
|
@@ -136,25 +144,22 @@ export const DefaultSidebarItemsGenerator: SidebarItemsGenerator = async ({
|
|
|
136
144
|
type: 'doc',
|
|
137
145
|
id,
|
|
138
146
|
position,
|
|
147
|
+
source: fileName,
|
|
139
148
|
// We don't want these fields to magically appear in the generated
|
|
140
149
|
// sidebar
|
|
141
150
|
...(label !== undefined && {label}),
|
|
142
151
|
...(className !== undefined && {className}),
|
|
143
152
|
};
|
|
144
153
|
}
|
|
145
|
-
|
|
154
|
+
function createCategoryItem(
|
|
146
155
|
dir: Dir,
|
|
147
156
|
fullPath: string,
|
|
148
157
|
folderName: string,
|
|
149
|
-
):
|
|
158
|
+
): WithPosition<NormalizedSidebarItemCategory> {
|
|
150
159
|
const categoryMetadata =
|
|
151
|
-
categoriesMetadata[
|
|
152
|
-
const
|
|
153
|
-
|
|
154
|
-
const allItems = await Promise.all(
|
|
155
|
-
Object.entries(dir).map(([key, content]) =>
|
|
156
|
-
dirToItem(content, key, `${fullPath}/${key}`),
|
|
157
|
-
),
|
|
160
|
+
categoriesMetadata[path.posix.join(autogenDir, fullPath)];
|
|
161
|
+
const allItems = Object.entries(dir).map(([key, content]) =>
|
|
162
|
+
dirToItem(content, key, `${fullPath}/${key}`),
|
|
158
163
|
);
|
|
159
164
|
|
|
160
165
|
// Try to match a doc inside the category folder,
|
|
@@ -176,59 +181,83 @@ export const DefaultSidebarItemsGenerator: SidebarItemsGenerator = async ({
|
|
|
176
181
|
});
|
|
177
182
|
}
|
|
178
183
|
|
|
179
|
-
function
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
+
// In addition to the ID, this function also retrieves metadata of the
|
|
185
|
+
// linked doc that could be used as fallback values for category metadata
|
|
186
|
+
function getCategoryLinkedDocMetadata():
|
|
187
|
+
| {
|
|
188
|
+
id: string;
|
|
189
|
+
position?: number;
|
|
190
|
+
label?: string;
|
|
191
|
+
customProps?: {[key: string]: unknown};
|
|
192
|
+
className?: string;
|
|
184
193
|
}
|
|
194
|
+
| undefined {
|
|
195
|
+
const link = categoryMetadata?.link;
|
|
196
|
+
if (link !== undefined && link?.type !== 'doc') {
|
|
185
197
|
// If a link is explicitly specified, we won't apply conventions
|
|
186
198
|
return undefined;
|
|
187
199
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
200
|
+
const id = link
|
|
201
|
+
? findDocByLocalId(link.id)?.id ?? getDoc(link.id).id
|
|
202
|
+
: findConventionalCategoryDocLink()?.id;
|
|
203
|
+
if (!id) {
|
|
204
|
+
return undefined;
|
|
205
|
+
}
|
|
206
|
+
const doc = getDoc(id);
|
|
207
|
+
return {
|
|
208
|
+
id,
|
|
209
|
+
position: doc.sidebarPosition,
|
|
210
|
+
label: doc.frontMatter.sidebar_label ?? doc.title,
|
|
211
|
+
customProps: doc.frontMatter.sidebar_custom_props,
|
|
212
|
+
className: doc.frontMatter.sidebar_class_name,
|
|
213
|
+
};
|
|
191
214
|
}
|
|
192
|
-
|
|
193
|
-
const categoryLinkedDocId = getCategoryLinkedDocId();
|
|
194
|
-
|
|
215
|
+
const categoryLinkedDoc = getCategoryLinkedDocMetadata();
|
|
195
216
|
const link: SidebarItemCategoryLinkConfig | null | undefined =
|
|
196
|
-
|
|
217
|
+
categoryLinkedDoc
|
|
197
218
|
? {
|
|
198
219
|
type: 'doc',
|
|
199
|
-
id:
|
|
220
|
+
id: categoryLinkedDoc.id, // We "remap" a potentially "local id" to a "qualified id"
|
|
200
221
|
}
|
|
201
222
|
: categoryMetadata?.link;
|
|
202
|
-
|
|
203
223
|
// If a doc is linked, remove it from the category subItems
|
|
204
224
|
const items = allItems.filter(
|
|
205
|
-
(item) => !(item.type === 'doc' && item.id ===
|
|
225
|
+
(item) => !(item.type === 'doc' && item.id === categoryLinkedDoc?.id),
|
|
206
226
|
);
|
|
207
227
|
|
|
228
|
+
const className =
|
|
229
|
+
categoryMetadata?.className ?? categoryLinkedDoc?.className;
|
|
230
|
+
const customProps =
|
|
231
|
+
categoryMetadata?.customProps ?? categoryLinkedDoc?.customProps;
|
|
232
|
+
const {filename, numberPrefix} = numberPrefixParser(folderName);
|
|
233
|
+
|
|
208
234
|
return {
|
|
209
235
|
type: 'category',
|
|
210
|
-
label: categoryMetadata?.label ?? filename,
|
|
236
|
+
label: categoryMetadata?.label ?? categoryLinkedDoc?.label ?? filename,
|
|
211
237
|
collapsible: categoryMetadata?.collapsible,
|
|
212
238
|
collapsed: categoryMetadata?.collapsed,
|
|
213
|
-
position:
|
|
239
|
+
position:
|
|
240
|
+
categoryMetadata?.position ??
|
|
241
|
+
categoryLinkedDoc?.position ??
|
|
242
|
+
numberPrefix,
|
|
243
|
+
source: folderName,
|
|
244
|
+
...(customProps !== undefined && {customProps}),
|
|
214
245
|
...(className !== undefined && {className}),
|
|
215
246
|
items,
|
|
216
247
|
...(link && {link}),
|
|
217
248
|
};
|
|
218
249
|
}
|
|
219
|
-
|
|
220
|
-
dir: Dir |
|
|
221
|
-
itemKey: string, //
|
|
250
|
+
function dirToItem(
|
|
251
|
+
dir: Dir | string, // The directory item to be transformed.
|
|
252
|
+
itemKey: string, // File/folder name; for categories, it's used to generate the next `relativePath`.
|
|
222
253
|
fullPath: string, // `dir`'s full path relative to the autogen dir.
|
|
223
|
-
):
|
|
224
|
-
return dir
|
|
254
|
+
): WithPosition<NormalizedSidebarItem> {
|
|
255
|
+
return typeof dir === 'object'
|
|
225
256
|
? createCategoryItem(dir, fullPath, itemKey)
|
|
226
|
-
: createDocItem(itemKey
|
|
257
|
+
: createDocItem(dir, fullPath, itemKey);
|
|
227
258
|
}
|
|
228
|
-
return
|
|
229
|
-
|
|
230
|
-
dirToItem(content, key, key),
|
|
231
|
-
),
|
|
259
|
+
return Object.entries(fsModel).map(([key, content]) =>
|
|
260
|
+
dirToItem(content, key, key),
|
|
232
261
|
);
|
|
233
262
|
}
|
|
234
263
|
|
|
@@ -248,16 +277,16 @@ export const DefaultSidebarItemsGenerator: SidebarItemsGenerator = async ({
|
|
|
248
277
|
}
|
|
249
278
|
return item;
|
|
250
279
|
});
|
|
251
|
-
const sortedSidebarItems = _.sortBy(
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
);
|
|
255
|
-
return sortedSidebarItems.map(({position, ...item}) => item);
|
|
280
|
+
const sortedSidebarItems = _.sortBy(processedSidebarItems, [
|
|
281
|
+
'position',
|
|
282
|
+
'source',
|
|
283
|
+
]);
|
|
284
|
+
return sortedSidebarItems.map(({position, source, ...item}) => item);
|
|
256
285
|
}
|
|
257
286
|
// TODO: the whole code is designed for pipeline operator
|
|
258
287
|
const docs = getAutogenDocs();
|
|
259
288
|
const fsModel = treeify(docs);
|
|
260
|
-
const sidebarWithPosition =
|
|
289
|
+
const sidebarWithPosition = generateSidebar(fsModel);
|
|
261
290
|
const sortedSidebar = sortItems(sidebarWithPosition);
|
|
262
291
|
return sortedSidebar;
|
|
263
292
|
};
|
package/src/sidebars/index.ts
CHANGED
|
@@ -32,7 +32,6 @@ export const DefaultSidebars: SidebarsConfig = {
|
|
|
32
32
|
export const DisabledSidebars: SidebarsConfig = {};
|
|
33
33
|
|
|
34
34
|
// If a path is provided, make it absolute
|
|
35
|
-
// use this before loadSidebars()
|
|
36
35
|
export function resolveSidebarPathOption(
|
|
37
36
|
siteDir: string,
|
|
38
37
|
sidebarPathOption: PluginOptions['sidebarPath'],
|
|
@@ -49,7 +48,7 @@ async function readCategoriesMetadata(contentPath: string) {
|
|
|
49
48
|
const categoryToFile = _.groupBy(categoryFiles, path.dirname);
|
|
50
49
|
return combinePromises(
|
|
51
50
|
_.mapValues(categoryToFile, async (files, folder) => {
|
|
52
|
-
const
|
|
51
|
+
const filePath = files[0]!;
|
|
53
52
|
if (files.length > 1) {
|
|
54
53
|
logger.warn`There are more than one category metadata files for path=${folder}: ${files.join(
|
|
55
54
|
', ',
|
|
@@ -93,21 +92,27 @@ export async function loadSidebarsFileUnsafe(
|
|
|
93
92
|
return importFresh(sidebarFilePath);
|
|
94
93
|
}
|
|
95
94
|
|
|
96
|
-
// Note: sidebarFilePath must be absolute, use resolveSidebarPathOption
|
|
97
95
|
export async function loadSidebars(
|
|
98
96
|
sidebarFilePath: string | false | undefined,
|
|
99
97
|
options: SidebarProcessorParams,
|
|
100
98
|
): Promise<Sidebars> {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
99
|
+
try {
|
|
100
|
+
const sidebarsConfig = await loadSidebarsFileUnsafe(sidebarFilePath);
|
|
101
|
+
const normalizedSidebars = normalizeSidebars(sidebarsConfig);
|
|
102
|
+
validateSidebars(normalizedSidebars);
|
|
103
|
+
const categoriesMetadata = await readCategoriesMetadata(
|
|
104
|
+
options.version.contentPath,
|
|
105
|
+
);
|
|
106
|
+
const processedSidebars = await processSidebars(
|
|
107
|
+
normalizedSidebars,
|
|
108
|
+
categoriesMetadata,
|
|
109
|
+
options,
|
|
110
|
+
);
|
|
111
|
+
return postProcessSidebars(processedSidebars, options);
|
|
112
|
+
} catch (err) {
|
|
113
|
+
logger.error`Sidebars file at path=${
|
|
114
|
+
sidebarFilePath as string
|
|
115
|
+
} failed to be loaded.`;
|
|
116
|
+
throw err;
|
|
117
|
+
}
|
|
113
118
|
}
|
|
@@ -65,7 +65,7 @@ function normalizeSidebar(
|
|
|
65
65
|
throw new Error(
|
|
66
66
|
logger.interpolate`Invalid sidebar items collection code=${JSON.stringify(
|
|
67
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
|
|
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 url=${'https://docusaurus.io/docs/sidebar/items'} for all valid syntaxes.`,
|
|
69
69
|
);
|
|
70
70
|
}
|
|
71
71
|
|
|
@@ -22,11 +22,11 @@ function normalizeCategoryLink(
|
|
|
22
22
|
params: SidebarProcessorParams,
|
|
23
23
|
): SidebarItemCategoryLink | undefined {
|
|
24
24
|
if (category.link?.type === 'generated-index') {
|
|
25
|
-
//
|
|
25
|
+
// Default slug logic can be improved
|
|
26
26
|
const getDefaultSlug = () =>
|
|
27
27
|
`/category/${params.categoryLabelSlugger.slug(category.label)}`;
|
|
28
28
|
const slug = category.link.slug ?? getDefaultSlug();
|
|
29
|
-
const permalink = normalizeUrl([params.version.
|
|
29
|
+
const permalink = normalizeUrl([params.version.path, slug]);
|
|
30
30
|
return {
|
|
31
31
|
...category.link,
|
|
32
32
|
slug,
|
|
@@ -58,22 +58,17 @@ function postProcessSidebarItem(
|
|
|
58
58
|
`Sidebar category ${item.label} has neither any subitem nor a link. This makes this item not able to link to anything.`,
|
|
59
59
|
);
|
|
60
60
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
return {
|
|
61
|
+
return category.link.type === 'doc'
|
|
62
|
+
? {
|
|
64
63
|
type: 'doc',
|
|
65
64
|
label: category.label,
|
|
66
65
|
id: category.link.id,
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
return {
|
|
66
|
+
}
|
|
67
|
+
: {
|
|
70
68
|
type: 'link',
|
|
71
69
|
label: category.label,
|
|
72
70
|
href: category.link.permalink,
|
|
73
71
|
};
|
|
74
|
-
default:
|
|
75
|
-
throw new Error('Unexpected sidebar category link type');
|
|
76
|
-
}
|
|
77
72
|
}
|
|
78
73
|
// A non-collapsible category can't be collapsed!
|
|
79
74
|
if (category.collapsible === false) {
|
|
@@ -5,7 +5,10 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import type {
|
|
8
|
+
import type {
|
|
9
|
+
DocMetadataBase,
|
|
10
|
+
VersionMetadata,
|
|
11
|
+
} from '@docusaurus/plugin-content-docs';
|
|
9
12
|
import type {
|
|
10
13
|
NormalizedSidebarItem,
|
|
11
14
|
NormalizedSidebar,
|
|
@@ -23,7 +26,7 @@ import {DefaultSidebarItemsGenerator} from './generator';
|
|
|
23
26
|
import {validateSidebars} from './validation';
|
|
24
27
|
import _ from 'lodash';
|
|
25
28
|
import combinePromises from 'combine-promises';
|
|
26
|
-
import {isCategoryIndex} from '../docs';
|
|
29
|
+
import {getDocIds, isCategoryIndex} from '../docs';
|
|
27
30
|
|
|
28
31
|
function toSidebarItemsGeneratorDoc(
|
|
29
32
|
doc: DocMetadataBase,
|
|
@@ -31,6 +34,7 @@ function toSidebarItemsGeneratorDoc(
|
|
|
31
34
|
return _.pick(doc, [
|
|
32
35
|
'id',
|
|
33
36
|
'unversionedId',
|
|
37
|
+
'title',
|
|
34
38
|
'frontMatter',
|
|
35
39
|
'source',
|
|
36
40
|
'sourceDirName',
|
|
@@ -48,16 +52,11 @@ function toSidebarItemsGeneratorVersion(
|
|
|
48
52
|
// post-processing checks
|
|
49
53
|
async function processSidebar(
|
|
50
54
|
unprocessedSidebar: NormalizedSidebar,
|
|
51
|
-
categoriesMetadata:
|
|
55
|
+
categoriesMetadata: {[filePath: string]: CategoryMetadataFile},
|
|
52
56
|
params: SidebarProcessorParams,
|
|
53
57
|
): Promise<ProcessedSidebar> {
|
|
54
|
-
const {
|
|
55
|
-
|
|
56
|
-
numberPrefixParser,
|
|
57
|
-
docs,
|
|
58
|
-
version,
|
|
59
|
-
sidebarOptions,
|
|
60
|
-
} = params;
|
|
58
|
+
const {sidebarItemsGenerator, numberPrefixParser, docs, drafts, version} =
|
|
59
|
+
params;
|
|
61
60
|
|
|
62
61
|
// Just a minor lazy transformation optimization
|
|
63
62
|
const getSidebarItemsGeneratorDocsAndVersion = _.memoize(() => ({
|
|
@@ -74,7 +73,6 @@ async function processSidebar(
|
|
|
74
73
|
defaultSidebarItemsGenerator: DefaultSidebarItemsGenerator,
|
|
75
74
|
isCategoryIndex,
|
|
76
75
|
...getSidebarItemsGeneratorDocsAndVersion(),
|
|
77
|
-
options: sidebarOptions,
|
|
78
76
|
categoriesMetadata,
|
|
79
77
|
});
|
|
80
78
|
// Process again... weird but sidebar item generated might generate some
|
|
@@ -84,6 +82,19 @@ async function processSidebar(
|
|
|
84
82
|
return processItems(generatedItems);
|
|
85
83
|
}
|
|
86
84
|
|
|
85
|
+
const draftIds = new Set(drafts.flatMap(getDocIds));
|
|
86
|
+
|
|
87
|
+
const isDraftItem = (item: NormalizedSidebarItem): boolean => {
|
|
88
|
+
if (item.type === 'doc' || item.type === 'ref') {
|
|
89
|
+
return draftIds.has(item.id);
|
|
90
|
+
}
|
|
91
|
+
// If a category only contains draft items, it should be filtered entirely.
|
|
92
|
+
if (item.type === 'category') {
|
|
93
|
+
return item.items.every(isDraftItem);
|
|
94
|
+
}
|
|
95
|
+
return false;
|
|
96
|
+
};
|
|
97
|
+
|
|
87
98
|
async function processItem(
|
|
88
99
|
item: NormalizedSidebarItem,
|
|
89
100
|
): Promise<ProcessedSidebarItem[]> {
|
|
@@ -91,7 +102,7 @@ async function processSidebar(
|
|
|
91
102
|
return [
|
|
92
103
|
{
|
|
93
104
|
...item,
|
|
94
|
-
items:
|
|
105
|
+
items: await processItems(item.items),
|
|
95
106
|
},
|
|
96
107
|
];
|
|
97
108
|
}
|
|
@@ -104,7 +115,9 @@ async function processSidebar(
|
|
|
104
115
|
async function processItems(
|
|
105
116
|
items: NormalizedSidebarItem[],
|
|
106
117
|
): Promise<ProcessedSidebarItem[]> {
|
|
107
|
-
return (
|
|
118
|
+
return (
|
|
119
|
+
await Promise.all(items.filter((i) => !isDraftItem(i)).map(processItem))
|
|
120
|
+
).flat();
|
|
108
121
|
}
|
|
109
122
|
|
|
110
123
|
const processedSidebar = await processItems(unprocessedSidebar);
|
|
@@ -113,7 +126,7 @@ async function processSidebar(
|
|
|
113
126
|
|
|
114
127
|
export async function processSidebars(
|
|
115
128
|
unprocessedSidebars: NormalizedSidebars,
|
|
116
|
-
categoriesMetadata:
|
|
129
|
+
categoriesMetadata: {[filePath: string]: CategoryMetadataFile},
|
|
117
130
|
params: SidebarProcessorParams,
|
|
118
131
|
): Promise<ProcessedSidebars> {
|
|
119
132
|
const processedSidebars = await combinePromises(
|