@docusaurus/plugin-content-docs 0.0.0-4523 → 0.0.0-4527
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 +8 -6
- package/lib/client/docsClientUtils.js +2 -2
- package/lib/client/globalDataHooks.js +4 -3
- package/lib/docs.d.ts +2 -1
- package/lib/docs.js +17 -15
- package/lib/index.js +1 -1
- package/lib/lastUpdate.js +6 -5
- package/lib/numberPrefix.js +7 -6
- package/lib/options.js +3 -2
- package/lib/routes.js +4 -2
- package/lib/sidebars/generator.js +20 -17
- package/lib/sidebars/index.d.ts +2 -2
- package/lib/sidebars/index.js +6 -6
- package/lib/sidebars/processor.js +6 -3
- package/lib/sidebars/utils.js +46 -54
- package/lib/sidebars/validation.js +7 -4
- package/lib/slug.js +6 -8
- package/lib/translations.js +7 -7
- package/lib/versions.js +11 -21
- package/package.json +9 -9
- package/src/cli.ts +9 -7
- package/src/client/docsClientUtils.ts +2 -2
- package/src/client/globalDataHooks.ts +4 -3
- package/src/docs.ts +17 -13
- package/src/index.ts +1 -1
- package/src/lastUpdate.ts +5 -5
- package/src/numberPrefix.ts +7 -6
- package/src/options.ts +3 -2
- package/src/plugin-content-docs.d.ts +2 -1
- package/src/routes.ts +4 -2
- package/src/sidebars/generator.ts +25 -19
- package/src/sidebars/index.ts +9 -9
- package/src/sidebars/processor.ts +6 -3
- package/src/sidebars/types.ts +2 -1
- package/src/sidebars/utils.ts +57 -61
- package/src/sidebars/validation.ts +7 -4
- package/src/slug.ts +9 -10
- package/src/translations.ts +7 -6
- package/src/versions.ts +13 -19
package/lib/cli.d.ts
CHANGED
|
@@ -5,4 +5,4 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
import type { PathOptions, SidebarOptions } from '@docusaurus/plugin-content-docs';
|
|
8
|
-
export declare function cliDocsVersionCommand(version: string | null | undefined, siteDir: string, pluginId: string, options: PathOptions & SidebarOptions): void
|
|
8
|
+
export declare function cliDocsVersionCommand(version: string | null | undefined, siteDir: string, pluginId: string, options: PathOptions & SidebarOptions): Promise<void>;
|
package/lib/cli.js
CHANGED
|
@@ -14,11 +14,13 @@ const path_1 = (0, tslib_1.__importDefault)(require("path"));
|
|
|
14
14
|
const sidebars_1 = require("./sidebars");
|
|
15
15
|
const utils_1 = require("@docusaurus/utils");
|
|
16
16
|
const logger_1 = (0, tslib_1.__importDefault)(require("@docusaurus/logger"));
|
|
17
|
-
function createVersionedSidebarFile({ siteDir, pluginId, sidebarPath, version, }) {
|
|
17
|
+
async function createVersionedSidebarFile({ siteDir, pluginId, sidebarPath, version, }) {
|
|
18
18
|
// Load current sidebar and create a new versioned sidebars file (if needed).
|
|
19
|
-
// Note: we don't need the sidebars file to be normalized: it's ok to let
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
// Note: we don't need the sidebars file to be normalized: it's ok to let
|
|
20
|
+
// plugin option changes to impact older, versioned sidebars
|
|
21
|
+
const sidebars = await (0, sidebars_1.loadSidebarsFile)(sidebarPath);
|
|
22
|
+
// Do not create a useless versioned sidebars file if sidebars file is empty
|
|
23
|
+
// or sidebars are disabled/false)
|
|
22
24
|
const shouldCreateVersionedSidebarFile = Object.keys(sidebars).length > 0;
|
|
23
25
|
if (shouldCreateVersionedSidebarFile) {
|
|
24
26
|
const versionedSidebarsDir = (0, versions_1.getVersionedSidebarsDirPath)(siteDir, pluginId);
|
|
@@ -28,7 +30,7 @@ function createVersionedSidebarFile({ siteDir, pluginId, sidebarPath, version, }
|
|
|
28
30
|
}
|
|
29
31
|
}
|
|
30
32
|
// Tests depend on non-default export for mocking.
|
|
31
|
-
function cliDocsVersionCommand(version, siteDir, pluginId, options) {
|
|
33
|
+
async function cliDocsVersionCommand(version, siteDir, pluginId, options) {
|
|
32
34
|
// It wouldn't be very user-friendly to show a [default] log prefix,
|
|
33
35
|
// so we use [docs] instead of [default]
|
|
34
36
|
const pluginIdLogPrefix = pluginId === utils_1.DEFAULT_PLUGIN_ID ? '[docs]' : `[${pluginId}]`;
|
|
@@ -71,7 +73,7 @@ function cliDocsVersionCommand(version, siteDir, pluginId, options) {
|
|
|
71
73
|
else {
|
|
72
74
|
throw new Error(`${pluginIdLogPrefix}: there is no docs to version!`);
|
|
73
75
|
}
|
|
74
|
-
createVersionedSidebarFile({
|
|
76
|
+
await createVersionedSidebarFile({
|
|
75
77
|
siteDir,
|
|
76
78
|
pluginId,
|
|
77
79
|
version,
|
|
@@ -14,7 +14,7 @@ const router_1 = require("@docusaurus/router");
|
|
|
14
14
|
// it is useful to support multiple docs plugin instances
|
|
15
15
|
function getActivePlugin(allPluginDatas, pathname, options = {}) {
|
|
16
16
|
const activeEntry = Object.entries(allPluginDatas)
|
|
17
|
-
//
|
|
17
|
+
// Route sorting: '/android/foo' should match '/android' instead of '/'
|
|
18
18
|
.sort((a, b) => b[1].path.localeCompare(a[1].path))
|
|
19
19
|
.find(([, pluginData]) => !!(0, router_1.matchPath)(pathname, {
|
|
20
20
|
path: pluginData.path,
|
|
@@ -39,7 +39,7 @@ exports.getLatestVersion = getLatestVersion;
|
|
|
39
39
|
const getActiveVersion = (data, pathname) => {
|
|
40
40
|
const lastVersion = (0, exports.getLatestVersion)(data);
|
|
41
41
|
// Last version is a route like /docs/*,
|
|
42
|
-
// we need to
|
|
42
|
+
// we need to match it last or it would match /docs/version-1.0/* as well
|
|
43
43
|
const orderedVersionsMetadata = [
|
|
44
44
|
...data.versions.filter((version) => version !== lastVersion),
|
|
45
45
|
lastVersion,
|
|
@@ -11,11 +11,12 @@ const tslib_1 = require("tslib");
|
|
|
11
11
|
const router_1 = require("@docusaurus/router");
|
|
12
12
|
const useGlobalData_1 = (0, tslib_1.__importStar)(require("@docusaurus/useGlobalData"));
|
|
13
13
|
const docsClientUtils_1 = require("./docsClientUtils");
|
|
14
|
-
// Important to use a constant object to avoid React useEffect executions etc
|
|
14
|
+
// Important to use a constant object to avoid React useEffect executions etc.
|
|
15
15
|
// see https://github.com/facebook/docusaurus/issues/5089
|
|
16
16
|
const StableEmptyObject = {};
|
|
17
|
-
// Not using useAllPluginInstancesData() because in blog-only mode, docs hooks
|
|
18
|
-
// We need a fail-safe fallback when the docs
|
|
17
|
+
// Not using useAllPluginInstancesData() because in blog-only mode, docs hooks
|
|
18
|
+
// are still used by the theme. We need a fail-safe fallback when the docs
|
|
19
|
+
// plugin is not in use
|
|
19
20
|
const useAllDocsData = () => { var _a;
|
|
20
21
|
// useAllPluginInstancesData('docusaurus-plugin-content-docs');
|
|
21
22
|
return (_a = (0, useGlobalData_1.default)()['docusaurus-plugin-content-docs']) !== null && _a !== void 0 ? _a : StableEmptyObject; };
|
package/lib/docs.d.ts
CHANGED
|
@@ -32,7 +32,8 @@ export declare function getMainDocId({ docs, sidebarsUtils, }: {
|
|
|
32
32
|
export declare const isCategoryIndex: CategoryIndexMatcher;
|
|
33
33
|
export declare function toCategoryIndexMatcherParam({ source, sourceDirName, }: Pick<DocMetadataBase, 'source' | 'sourceDirName'>): CategoryIndexMatcherParam;
|
|
34
34
|
/**
|
|
35
|
-
* guides/sidebar/autogenerated.md ->
|
|
35
|
+
* `guides/sidebar/autogenerated.md` ->
|
|
36
|
+
* `'autogenerated', '.md', ['sidebar', 'guides']`
|
|
36
37
|
*/
|
|
37
38
|
export declare function splitPath(str: string): {
|
|
38
39
|
/**
|
package/lib/docs.js
CHANGED
|
@@ -65,7 +65,8 @@ function doProcessDocMetadata({ docFile, versionMetadata, context, options, }) {
|
|
|
65
65
|
const { frontMatter: unsafeFrontMatter, contentTitle, excerpt, } = (0, utils_1.parseMarkdownString)(content);
|
|
66
66
|
const frontMatter = (0, docFrontMatter_1.validateDocFrontMatter)(unsafeFrontMatter);
|
|
67
67
|
const { custom_edit_url: customEditURL,
|
|
68
|
-
// Strip number prefixes by default
|
|
68
|
+
// Strip number prefixes by default
|
|
69
|
+
// (01-MyFolder/01-MyDoc.md => MyFolder/MyDoc)
|
|
69
70
|
// but allow to disable this behavior with front matter
|
|
70
71
|
parse_number_prefixes: parseNumberPrefixes = true, } = frontMatter;
|
|
71
72
|
// ex: api/plugins/myDoc -> myDoc
|
|
@@ -81,7 +82,8 @@ function doProcessDocMetadata({ docFile, versionMetadata, context, options, }) {
|
|
|
81
82
|
if (baseID.includes('/')) {
|
|
82
83
|
throw new Error(`Document id "${baseID}" cannot include slash.`);
|
|
83
84
|
}
|
|
84
|
-
// For autogenerated sidebars, sidebar position can come from filename number
|
|
85
|
+
// For autogenerated sidebars, sidebar position can come from filename number
|
|
86
|
+
// prefix or front matter
|
|
85
87
|
const sidebarPosition = (_b = frontMatter.sidebar_position) !== null && _b !== void 0 ? _b : numberPrefix;
|
|
86
88
|
// TODO legacy retrocompatibility
|
|
87
89
|
// The same doc in 2 distinct version could keep the same id,
|
|
@@ -114,8 +116,9 @@ function doProcessDocMetadata({ docFile, versionMetadata, context, options, }) {
|
|
|
114
116
|
stripDirNumberPrefixes: parseNumberPrefixes,
|
|
115
117
|
numberPrefixParser: options.numberPrefixParser,
|
|
116
118
|
});
|
|
117
|
-
// Note: the title is used by default for page title, sidebar label,
|
|
118
|
-
// frontMatter.title should be used in priority over
|
|
119
|
+
// Note: the title is used by default for page title, sidebar label,
|
|
120
|
+
// pagination buttons... frontMatter.title should be used in priority over
|
|
121
|
+
// contentTitle (because it can contain markdown/JSX syntax)
|
|
119
122
|
const title = (_d = (_c = frontMatter.title) !== null && _c !== void 0 ? _c : contentTitle) !== null && _d !== void 0 ? _d : baseID;
|
|
120
123
|
const description = (_f = (_e = frontMatter.description) !== null && _e !== void 0 ? _e : excerpt) !== null && _f !== void 0 ? _f : '';
|
|
121
124
|
const permalink = (0, utils_1.normalizeUrl)([versionMetadata.versionPath, docSlug]);
|
|
@@ -137,9 +140,7 @@ function doProcessDocMetadata({ docFile, versionMetadata, context, options, }) {
|
|
|
137
140
|
: versionMetadata.versionEditUrl;
|
|
138
141
|
return (0, utils_1.getEditUrl)(relativeFilePath, baseVersionEditUrl);
|
|
139
142
|
}
|
|
140
|
-
|
|
141
|
-
return undefined;
|
|
142
|
-
}
|
|
143
|
+
return undefined;
|
|
143
144
|
}
|
|
144
145
|
// Assign all of object properties during instantiation (if possible) for
|
|
145
146
|
// NodeJS optimization.
|
|
@@ -225,9 +226,7 @@ function getMainDocId({ docs, sidebarsUtils, }) {
|
|
|
225
226
|
return docs.find((doc) => doc.id === firstDocIdOfFirstSidebar ||
|
|
226
227
|
doc.unversionedId === firstDocIdOfFirstSidebar);
|
|
227
228
|
}
|
|
228
|
-
|
|
229
|
-
return docs[0];
|
|
230
|
-
}
|
|
229
|
+
return docs[0];
|
|
231
230
|
}
|
|
232
231
|
return getMainDoc().unversionedId;
|
|
233
232
|
}
|
|
@@ -262,7 +261,8 @@ function toCategoryIndexMatcherParam({ source, sourceDirName, }) {
|
|
|
262
261
|
}
|
|
263
262
|
exports.toCategoryIndexMatcherParam = toCategoryIndexMatcherParam;
|
|
264
263
|
/**
|
|
265
|
-
* guides/sidebar/autogenerated.md ->
|
|
264
|
+
* `guides/sidebar/autogenerated.md` ->
|
|
265
|
+
* `'autogenerated', '.md', ['sidebar', 'guides']`
|
|
266
266
|
*/
|
|
267
267
|
function splitPath(str) {
|
|
268
268
|
return {
|
|
@@ -273,15 +273,17 @@ function splitPath(str) {
|
|
|
273
273
|
}
|
|
274
274
|
exports.splitPath = splitPath;
|
|
275
275
|
// Return both doc ids
|
|
276
|
-
// TODO legacy retro-compatibility due to old versioned sidebars using
|
|
277
|
-
// ("id" should be removed & "versionedId" should be renamed
|
|
276
|
+
// TODO legacy retro-compatibility due to old versioned sidebars using
|
|
277
|
+
// versioned doc ids ("id" should be removed & "versionedId" should be renamed
|
|
278
|
+
// to "id")
|
|
278
279
|
function getDocIds(doc) {
|
|
279
280
|
return [doc.unversionedId, doc.id];
|
|
280
281
|
}
|
|
281
282
|
exports.getDocIds = getDocIds;
|
|
282
283
|
// docs are indexed by both versioned and unversioned ids at the same time
|
|
283
|
-
// TODO legacy retro-compatibility due to old versioned sidebars using
|
|
284
|
-
// ("id" should be removed & "versionedId" should be renamed
|
|
284
|
+
// TODO legacy retro-compatibility due to old versioned sidebars using
|
|
285
|
+
// versioned doc ids ("id" should be removed & "versionedId" should be renamed
|
|
286
|
+
// to "id")
|
|
285
287
|
function createDocsByIdIndex(docs) {
|
|
286
288
|
return {
|
|
287
289
|
...(0, lodash_1.keyBy)(docs, (doc) => doc.unversionedId),
|
package/lib/index.js
CHANGED
|
@@ -214,7 +214,7 @@ async function pluginContentDocs(context, options) {
|
|
|
214
214
|
function createMDXLoaderRule() {
|
|
215
215
|
const contentDirs = versionsMetadata.flatMap(versions_1.getDocsDirPaths);
|
|
216
216
|
return {
|
|
217
|
-
test:
|
|
217
|
+
test: /\.mdx?$/i,
|
|
218
218
|
include: contentDirs
|
|
219
219
|
// Trailing slash is important, see https://github.com/facebook/docusaurus/pull/3970
|
|
220
220
|
.map(utils_1.addTrailingPathSeparator),
|
package/lib/lastUpdate.js
CHANGED
|
@@ -10,20 +10,21 @@ exports.getFileLastUpdate = void 0;
|
|
|
10
10
|
const tslib_1 = require("tslib");
|
|
11
11
|
const shelljs_1 = (0, tslib_1.__importDefault)(require("shelljs"));
|
|
12
12
|
const logger_1 = (0, tslib_1.__importDefault)(require("@docusaurus/logger"));
|
|
13
|
-
const GIT_COMMIT_TIMESTAMP_AUTHOR_REGEX = /^(
|
|
13
|
+
const GIT_COMMIT_TIMESTAMP_AUTHOR_REGEX = /^(?<timestamp>\d+),(?<author>.+)$/;
|
|
14
14
|
let showedGitRequirementError = false;
|
|
15
15
|
async function getFileLastUpdate(filePath) {
|
|
16
16
|
if (!filePath) {
|
|
17
17
|
return null;
|
|
18
18
|
}
|
|
19
19
|
function getTimestampAndAuthor(str) {
|
|
20
|
+
var _a;
|
|
20
21
|
if (!str) {
|
|
21
22
|
return null;
|
|
22
23
|
}
|
|
23
|
-
const temp = str.match(GIT_COMMIT_TIMESTAMP_AUTHOR_REGEX);
|
|
24
|
-
return
|
|
25
|
-
?
|
|
26
|
-
:
|
|
24
|
+
const temp = (_a = str.match(GIT_COMMIT_TIMESTAMP_AUTHOR_REGEX)) === null || _a === void 0 ? void 0 : _a.groups;
|
|
25
|
+
return temp
|
|
26
|
+
? { timestamp: Number(temp.timestamp), author: temp.author }
|
|
27
|
+
: null;
|
|
27
28
|
}
|
|
28
29
|
// Wrap in try/catch in case the shell commands fail
|
|
29
30
|
// (e.g. project doesn't use Git, etc).
|
package/lib/numberPrefix.js
CHANGED
|
@@ -8,14 +8,15 @@
|
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
9
|
exports.stripPathNumberPrefixes = exports.stripNumberPrefix = exports.DisabledNumberPrefixParser = exports.DefaultNumberPrefixParser = void 0;
|
|
10
10
|
// Best-effort to avoid parsing some patterns as number prefix
|
|
11
|
-
const IgnoredPrefixPatterns = (
|
|
11
|
+
const IgnoredPrefixPatterns = (() => {
|
|
12
12
|
// ignore common date-like patterns: https://github.com/facebook/docusaurus/issues/4640
|
|
13
|
-
const DateLikePrefixRegex = /^(
|
|
13
|
+
const DateLikePrefixRegex = /^(?:\d{2}|\d{4})[-_.]\d{2}(?:[-_.](?:\d{2}|\d{4}))?.*$/;
|
|
14
14
|
// ignore common versioning patterns: https://github.com/facebook/docusaurus/issues/4653
|
|
15
|
-
// note: we could try to parse float numbers in filenames but that is
|
|
16
|
-
// as a version such as "8.0" can be interpreted as both
|
|
17
|
-
// User can configure
|
|
18
|
-
|
|
15
|
+
// note: we could try to parse float numbers in filenames but that is
|
|
16
|
+
// probably not worth it as a version such as "8.0" can be interpreted as both
|
|
17
|
+
// a version and a float. User can configure her own NumberPrefixParser if
|
|
18
|
+
// she wants 8.0 to be interpreted as a float
|
|
19
|
+
const VersionLikePrefixRegex = /^\d+[-_.]\d+.*$/;
|
|
19
20
|
return new RegExp(`${DateLikePrefixRegex.source}|${VersionLikePrefixRegex.source}`);
|
|
20
21
|
})();
|
|
21
22
|
const NumberPrefixRegex = /^(?<numberPrefix>\d+)(?<separator>\s*[-_.]+\s*)(?<suffix>.*)$/;
|
package/lib/options.js
CHANGED
|
@@ -102,8 +102,9 @@ exports.OptionsSchema = utils_validation_1.Joi.object({
|
|
|
102
102
|
function validateOptions({ validate, options: userOptions, }) {
|
|
103
103
|
let options = userOptions;
|
|
104
104
|
if (options.sidebarCollapsible === false) {
|
|
105
|
-
// When sidebarCollapsible=false and sidebarCollapsed=undefined, we don't
|
|
106
|
-
//
|
|
105
|
+
// When sidebarCollapsible=false and sidebarCollapsed=undefined, we don't
|
|
106
|
+
// want to have the inconsistency warning. We let options.sidebarCollapsible
|
|
107
|
+
// become the default value for options.sidebarCollapsed
|
|
107
108
|
if (typeof options.sidebarCollapsed === 'undefined') {
|
|
108
109
|
options = {
|
|
109
110
|
...options,
|
package/lib/routes.js
CHANGED
|
@@ -36,7 +36,8 @@ async function createCategoryGeneratedIndexRoutes({ version, actions, docCategor
|
|
|
36
36
|
modules: {
|
|
37
37
|
categoryGeneratedIndex: aliasedSource(propData),
|
|
38
38
|
},
|
|
39
|
-
// Same as doc, this sidebar route attribute permits to associate this
|
|
39
|
+
// Same as doc, this sidebar route attribute permits to associate this
|
|
40
|
+
// subpage to the given sidebar
|
|
40
41
|
...(sidebar && { sidebar }),
|
|
41
42
|
};
|
|
42
43
|
}
|
|
@@ -57,7 +58,8 @@ async function createDocRoutes({ docs, actions, docItemComponent, }) {
|
|
|
57
58
|
content: metadataItem.source,
|
|
58
59
|
},
|
|
59
60
|
// Because the parent (DocPage) comp need to access it easily
|
|
60
|
-
// This permits to render the sidebar once without unmount/remount when
|
|
61
|
+
// This permits to render the sidebar once without unmount/remount when
|
|
62
|
+
// navigating (and preserve sidebar state)
|
|
61
63
|
...(metadataItem.sidebar && {
|
|
62
64
|
sidebar: metadataItem.sidebar,
|
|
63
65
|
}),
|
|
@@ -25,9 +25,12 @@ function getLocalDocId(docId) {
|
|
|
25
25
|
}
|
|
26
26
|
exports.CategoryMetadataFilenameBase = '_category_';
|
|
27
27
|
exports.CategoryMetadataFilenamePattern = '_category_.{json,yml,yaml}';
|
|
28
|
-
// TODO I now believe we should read all the category metadata files ahead of
|
|
29
|
-
//
|
|
30
|
-
//
|
|
28
|
+
// TODO I now believe we should read all the category metadata files ahead of
|
|
29
|
+
// time: we may need this metadata to customize docs metadata
|
|
30
|
+
// Example use-case being able to disable number prefix parsing at the folder
|
|
31
|
+
// level, or customize the default base slug for an intermediate directory
|
|
32
|
+
// TODO later if there is `CategoryFolder/with-category-name-doc.md`, we may
|
|
33
|
+
// want to read the metadata as yaml on it
|
|
31
34
|
// see https://github.com/facebook/docusaurus/issues/3464#issuecomment-818670449
|
|
32
35
|
async function readCategoryMetadataFile(categoryDirPath) {
|
|
33
36
|
async function tryReadFile(filePath) {
|
|
@@ -79,7 +82,8 @@ const DefaultSidebarItemsGenerator = async ({ numberPrefixParser, isCategoryInde
|
|
|
79
82
|
* Step 2. Turn the linear file list into a tree structure.
|
|
80
83
|
*/
|
|
81
84
|
function treeify(docs) {
|
|
82
|
-
// Get the category breadcrumb of a doc (relative to the dir of the
|
|
85
|
+
// Get the category breadcrumb of a doc (relative to the dir of the
|
|
86
|
+
// autogenerated sidebar item)
|
|
83
87
|
// autogenDir=a/b and docDir=a/b/c/d => returns [c, d]
|
|
84
88
|
// autogenDir=a/b and docDir=a/b => returns []
|
|
85
89
|
// TODO: try to use path.relative()
|
|
@@ -105,7 +109,7 @@ const DefaultSidebarItemsGenerator = async ({ numberPrefixParser, isCategoryInde
|
|
|
105
109
|
return treeRoot;
|
|
106
110
|
}
|
|
107
111
|
/**
|
|
108
|
-
* Step 3. Recursively transform the tree-like
|
|
112
|
+
* Step 3. Recursively transform the tree-like structure to sidebar items.
|
|
109
113
|
* (From a record to an array of items, akin to normalizing shorthand)
|
|
110
114
|
*/
|
|
111
115
|
function generateSidebar(fsModel) {
|
|
@@ -115,7 +119,8 @@ const DefaultSidebarItemsGenerator = async ({ numberPrefixParser, isCategoryInde
|
|
|
115
119
|
type: 'doc',
|
|
116
120
|
id,
|
|
117
121
|
position,
|
|
118
|
-
// We don't want these fields to magically appear in the generated
|
|
122
|
+
// We don't want these fields to magically appear in the generated
|
|
123
|
+
// sidebar
|
|
119
124
|
...(label !== undefined && { label }),
|
|
120
125
|
...(className !== undefined && { className }),
|
|
121
126
|
};
|
|
@@ -148,13 +153,11 @@ const DefaultSidebarItemsGenerator = async ({ numberPrefixParser, isCategoryInde
|
|
|
148
153
|
if (link && link.type === 'doc') {
|
|
149
154
|
return ((_a = findDocByLocalId(link.id)) === null || _a === void 0 ? void 0 : _a.id) || getDoc(link.id).id;
|
|
150
155
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
// IE if user decide to use type "generated-index", we should not pick a README.md file as the linked doc
|
|
154
|
-
return undefined;
|
|
155
|
-
}
|
|
156
|
+
// If a link is explicitly specified, we won't apply conventions
|
|
157
|
+
return undefined;
|
|
156
158
|
}
|
|
157
|
-
// Apply default convention to pick index.md, README.md or
|
|
159
|
+
// Apply default convention to pick index.md, README.md or
|
|
160
|
+
// <categoryName>.md as the category doc
|
|
158
161
|
return (_b = findConventionalCategoryDocLink()) === null || _b === void 0 ? void 0 : _b.id;
|
|
159
162
|
}
|
|
160
163
|
const categoryLinkedDocId = getCategoryLinkedDocId();
|
|
@@ -188,10 +191,11 @@ const DefaultSidebarItemsGenerator = async ({ numberPrefixParser, isCategoryInde
|
|
|
188
191
|
return Promise.all(Object.entries(fsModel).map(([key, content]) => dirToItem(content, key, key)));
|
|
189
192
|
}
|
|
190
193
|
/**
|
|
191
|
-
* Step 4. Recursively sort the categories/docs + remove the "position"
|
|
192
|
-
* Note: the "position" is only used to sort
|
|
193
|
-
*
|
|
194
|
-
* composed of multiple
|
|
194
|
+
* Step 4. Recursively sort the categories/docs + remove the "position"
|
|
195
|
+
* attribute from final output. Note: the "position" is only used to sort
|
|
196
|
+
* "inside" a sidebar slice. It is not used to sort across multiple
|
|
197
|
+
* consecutive sidebar slices (i.e. a whole category composed of multiple
|
|
198
|
+
* autogenerated items)
|
|
195
199
|
*/
|
|
196
200
|
function sortItems(sidebarItems) {
|
|
197
201
|
const processedSidebarItems = sidebarItems.map((item) => {
|
|
@@ -204,7 +208,6 @@ const DefaultSidebarItemsGenerator = async ({ numberPrefixParser, isCategoryInde
|
|
|
204
208
|
return sortedSidebarItems.map(({ position, ...item }) => item);
|
|
205
209
|
}
|
|
206
210
|
// TODO: the whole code is designed for pipeline operator
|
|
207
|
-
// return getAutogenDocs() |> treeify |> await generateSidebar(^) |> sortItems;
|
|
208
211
|
const docs = getAutogenDocs();
|
|
209
212
|
const fsModel = treeify(docs);
|
|
210
213
|
const sidebarWithPosition = await generateSidebar(fsModel);
|
package/lib/sidebars/index.d.ts
CHANGED
|
@@ -11,6 +11,6 @@ import type { PluginOptions } from '@docusaurus/plugin-content-docs';
|
|
|
11
11
|
export declare const DefaultSidebars: SidebarsConfig;
|
|
12
12
|
export declare const DisabledSidebars: SidebarsConfig;
|
|
13
13
|
export declare function resolveSidebarPathOption(siteDir: string, sidebarPathOption: PluginOptions['sidebarPath']): PluginOptions['sidebarPath'];
|
|
14
|
-
export declare function loadSidebarsFile(sidebarFilePath: string | false | undefined): SidebarsConfig
|
|
15
|
-
export declare function loadNormalizedSidebars(sidebarFilePath: string | false | undefined, params: NormalizeSidebarsParams): NormalizedSidebars
|
|
14
|
+
export declare function loadSidebarsFile(sidebarFilePath: string | false | undefined): Promise<SidebarsConfig>;
|
|
15
|
+
export declare function loadNormalizedSidebars(sidebarFilePath: string | false | undefined, params: NormalizeSidebarsParams): Promise<NormalizedSidebars>;
|
|
16
16
|
export declare function loadSidebars(sidebarFilePath: string | false | undefined, options: SidebarProcessorParams): Promise<Sidebars>;
|
package/lib/sidebars/index.js
CHANGED
|
@@ -32,7 +32,7 @@ function resolveSidebarPathOption(siteDir, sidebarPathOption) {
|
|
|
32
32
|
: sidebarPathOption;
|
|
33
33
|
}
|
|
34
34
|
exports.resolveSidebarPathOption = resolveSidebarPathOption;
|
|
35
|
-
function loadSidebarsFileUnsafe(sidebarFilePath) {
|
|
35
|
+
async function loadSidebarsFileUnsafe(sidebarFilePath) {
|
|
36
36
|
// false => no sidebars
|
|
37
37
|
if (sidebarFilePath === false) {
|
|
38
38
|
return exports.DisabledSidebars;
|
|
@@ -50,14 +50,14 @@ function loadSidebarsFileUnsafe(sidebarFilePath) {
|
|
|
50
50
|
// We don't want sidebars to be cached because of hot reloading.
|
|
51
51
|
return (0, import_fresh_1.default)(sidebarFilePath);
|
|
52
52
|
}
|
|
53
|
-
function loadSidebarsFile(sidebarFilePath) {
|
|
54
|
-
const sidebarsConfig = loadSidebarsFileUnsafe(sidebarFilePath);
|
|
53
|
+
async function loadSidebarsFile(sidebarFilePath) {
|
|
54
|
+
const sidebarsConfig = await loadSidebarsFileUnsafe(sidebarFilePath);
|
|
55
55
|
(0, validation_1.validateSidebars)(sidebarsConfig);
|
|
56
56
|
return sidebarsConfig;
|
|
57
57
|
}
|
|
58
58
|
exports.loadSidebarsFile = loadSidebarsFile;
|
|
59
|
-
function loadNormalizedSidebars(sidebarFilePath, params) {
|
|
60
|
-
return (0, normalization_1.normalizeSidebars)(loadSidebarsFile(sidebarFilePath), params);
|
|
59
|
+
async function loadNormalizedSidebars(sidebarFilePath, params) {
|
|
60
|
+
return (0, normalization_1.normalizeSidebars)(await loadSidebarsFile(sidebarFilePath), params);
|
|
61
61
|
}
|
|
62
62
|
exports.loadNormalizedSidebars = loadNormalizedSidebars;
|
|
63
63
|
// Note: sidebarFilePath must be absolute, use resolveSidebarPathOption
|
|
@@ -67,7 +67,7 @@ async function loadSidebars(sidebarFilePath, options) {
|
|
|
67
67
|
version: options.version,
|
|
68
68
|
categoryLabelSlugger: (0, utils_1.createSlugger)(),
|
|
69
69
|
};
|
|
70
|
-
const normalizedSidebars = loadNormalizedSidebars(sidebarFilePath, normalizeSidebarsParams);
|
|
70
|
+
const normalizedSidebars = await loadNormalizedSidebars(sidebarFilePath, normalizeSidebarsParams);
|
|
71
71
|
return (0, processor_1.processSidebars)(normalizedSidebars, options);
|
|
72
72
|
}
|
|
73
73
|
exports.loadSidebars = loadSidebars;
|
|
@@ -27,7 +27,8 @@ function toSidebarItemsGeneratorDoc(doc) {
|
|
|
27
27
|
function toSidebarItemsGeneratorVersion(version) {
|
|
28
28
|
return (0, lodash_1.pick)(version, ['versionName', 'contentPath']);
|
|
29
29
|
}
|
|
30
|
-
// Handle the generation of autogenerated sidebar items and other
|
|
30
|
+
// Handle the generation of autogenerated sidebar items and other
|
|
31
|
+
// post-processing checks
|
|
31
32
|
async function processSidebar(unprocessedSidebar, params) {
|
|
32
33
|
const { sidebarItemsGenerator, numberPrefixParser, docs, version, sidebarOptions, } = params;
|
|
33
34
|
// Just a minor lazy transformation optimization
|
|
@@ -42,7 +43,8 @@ async function processSidebar(unprocessedSidebar, params) {
|
|
|
42
43
|
};
|
|
43
44
|
}
|
|
44
45
|
async function processAutoGeneratedItem(item) {
|
|
45
|
-
// TODO the returned type can't be trusted in practice (generator can be
|
|
46
|
+
// TODO the returned type can't be trusted in practice (generator can be
|
|
47
|
+
// user-provided)
|
|
46
48
|
const generatedItems = await sidebarItemsGenerator({
|
|
47
49
|
item,
|
|
48
50
|
numberPrefixParser,
|
|
@@ -53,7 +55,8 @@ async function processSidebar(unprocessedSidebar, params) {
|
|
|
53
55
|
});
|
|
54
56
|
// TODO validate generated items: user can generate bad items
|
|
55
57
|
const generatedItemsNormalized = generatedItems.flatMap((generatedItem) => (0, normalization_1.normalizeItem)(generatedItem, { ...params, ...sidebarOptions }));
|
|
56
|
-
// Process again... weird but sidebar item generated might generate some
|
|
58
|
+
// Process again... weird but sidebar item generated might generate some
|
|
59
|
+
// auto-generated items?
|
|
57
60
|
return processItems(generatedItemsNormalized);
|
|
58
61
|
}
|
|
59
62
|
async function processItem(item) {
|
package/lib/sidebars/utils.js
CHANGED
|
@@ -26,8 +26,11 @@ function transformSidebarItems(sidebar, updateFn) {
|
|
|
26
26
|
return sidebar.map(transformRecursive);
|
|
27
27
|
}
|
|
28
28
|
exports.transformSidebarItems = transformSidebarItems;
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Flatten sidebar items into a single flat array (containing categories/docs on
|
|
31
|
+
* the same level). Order matters (useful for next/prev nav), top categories
|
|
32
|
+
* appear before their child elements
|
|
33
|
+
*/
|
|
31
34
|
function flattenSidebarItems(items) {
|
|
32
35
|
function flattenRecursive(item) {
|
|
33
36
|
return item.type === 'category'
|
|
@@ -114,29 +117,27 @@ function createSidebarsUtils(sidebars) {
|
|
|
114
117
|
docId = versionedId;
|
|
115
118
|
sidebarName = getSidebarNameByDocId(docId);
|
|
116
119
|
}
|
|
117
|
-
if (sidebarName) {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
+
if (!sidebarName) {
|
|
121
|
+
return emptySidebarNavigation();
|
|
122
|
+
}
|
|
123
|
+
if (!sidebarNameToNavigationItems[sidebarName]) {
|
|
124
|
+
throw new Error(`Doc with ID ${docId} wants to display sidebar ${sidebarName} but a sidebar with this name doesn't exist`);
|
|
125
|
+
}
|
|
126
|
+
const navigationItems = sidebarNameToNavigationItems[sidebarName];
|
|
127
|
+
const currentItemIndex = navigationItems.findIndex((item) => {
|
|
128
|
+
if (item.type === 'doc') {
|
|
129
|
+
return item.id === docId;
|
|
120
130
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
if (item.type === 'doc') {
|
|
124
|
-
return item.id === docId;
|
|
125
|
-
}
|
|
126
|
-
if (item.type === 'category' && item.link.type === 'doc') {
|
|
127
|
-
return item.link.id === docId;
|
|
128
|
-
}
|
|
129
|
-
return false;
|
|
130
|
-
});
|
|
131
|
-
if (currentItemIndex === -1) {
|
|
132
|
-
return { sidebarName, next: undefined, previous: undefined };
|
|
131
|
+
if (item.type === 'category' && item.link.type === 'doc') {
|
|
132
|
+
return item.link.id === docId;
|
|
133
133
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
return emptySidebarNavigation();
|
|
134
|
+
return false;
|
|
135
|
+
});
|
|
136
|
+
if (currentItemIndex === -1) {
|
|
137
|
+
return { sidebarName, next: undefined, previous: undefined };
|
|
139
138
|
}
|
|
139
|
+
const { previous, next } = (0, utils_1.getElementsAround)(navigationItems, currentItemIndex);
|
|
140
|
+
return { sidebarName, previous, next };
|
|
140
141
|
}
|
|
141
142
|
function getCategoryGeneratedIndexList() {
|
|
142
143
|
return Object.values(sidebarNameToNavigationItems)
|
|
@@ -148,8 +149,10 @@ function createSidebarsUtils(sidebars) {
|
|
|
148
149
|
return [];
|
|
149
150
|
});
|
|
150
151
|
}
|
|
151
|
-
|
|
152
|
-
|
|
152
|
+
/**
|
|
153
|
+
* We identity the category generated index by its permalink (should be
|
|
154
|
+
* unique). More reliable than using object identity
|
|
155
|
+
*/
|
|
153
156
|
function getCategoryGeneratedIndexNavigation(categoryGeneratedIndexPermalink) {
|
|
154
157
|
var _a;
|
|
155
158
|
function isCurrentCategoryGeneratedIndexItem(item) {
|
|
@@ -159,15 +162,13 @@ function createSidebarsUtils(sidebars) {
|
|
|
159
162
|
item.link.permalink === categoryGeneratedIndexPermalink);
|
|
160
163
|
}
|
|
161
164
|
const sidebarName = (_a = Object.entries(sidebarNameToNavigationItems).find(([, navigationItems]) => navigationItems.find(isCurrentCategoryGeneratedIndexItem))) === null || _a === void 0 ? void 0 : _a[0];
|
|
162
|
-
if (sidebarName) {
|
|
163
|
-
const navigationItems = sidebarNameToNavigationItems[sidebarName];
|
|
164
|
-
const currentItemIndex = navigationItems.findIndex(isCurrentCategoryGeneratedIndexItem);
|
|
165
|
-
const { previous, next } = (0, utils_1.getElementsAround)(navigationItems, currentItemIndex);
|
|
166
|
-
return { sidebarName, previous, next };
|
|
167
|
-
}
|
|
168
|
-
else {
|
|
165
|
+
if (!sidebarName) {
|
|
169
166
|
return emptySidebarNavigation();
|
|
170
167
|
}
|
|
168
|
+
const navigationItems = sidebarNameToNavigationItems[sidebarName];
|
|
169
|
+
const currentItemIndex = navigationItems.findIndex(isCurrentCategoryGeneratedIndexItem);
|
|
170
|
+
const { previous, next } = (0, utils_1.getElementsAround)(navigationItems, currentItemIndex);
|
|
171
|
+
return { sidebarName, previous, next };
|
|
171
172
|
}
|
|
172
173
|
function checkSidebarsDocIds(validDocIds, sidebarFilePath) {
|
|
173
174
|
const allSidebarDocIds = Object.values(sidebarNameToDocIds).flat();
|
|
@@ -207,11 +208,9 @@ Available document ids are:
|
|
|
207
208
|
label: item.label,
|
|
208
209
|
};
|
|
209
210
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
return firstSubItem;
|
|
214
|
-
}
|
|
211
|
+
const firstSubItem = getFirstLink(item.items);
|
|
212
|
+
if (firstSubItem) {
|
|
213
|
+
return firstSubItem;
|
|
215
214
|
}
|
|
216
215
|
}
|
|
217
216
|
}
|
|
@@ -243,20 +242,6 @@ function toNavigationLink(navigationItem, docsById) {
|
|
|
243
242
|
}
|
|
244
243
|
return doc;
|
|
245
244
|
}
|
|
246
|
-
function handleCategory(category) {
|
|
247
|
-
if (category.link.type === 'doc') {
|
|
248
|
-
return toDocNavigationLink(getDocById(category.link.id));
|
|
249
|
-
}
|
|
250
|
-
else if (category.link.type === 'generated-index') {
|
|
251
|
-
return {
|
|
252
|
-
title: category.label,
|
|
253
|
-
permalink: category.link.permalink,
|
|
254
|
-
};
|
|
255
|
-
}
|
|
256
|
-
else {
|
|
257
|
-
throw new Error('unexpected category link type');
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
245
|
if (!navigationItem) {
|
|
261
246
|
return undefined;
|
|
262
247
|
}
|
|
@@ -264,10 +249,17 @@ function toNavigationLink(navigationItem, docsById) {
|
|
|
264
249
|
return toDocNavigationLink(getDocById(navigationItem.id));
|
|
265
250
|
}
|
|
266
251
|
else if (navigationItem.type === 'category') {
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
252
|
+
if (navigationItem.link.type === 'doc') {
|
|
253
|
+
return toDocNavigationLink(getDocById(navigationItem.link.id));
|
|
254
|
+
}
|
|
255
|
+
else if (navigationItem.link.type === 'generated-index') {
|
|
256
|
+
return {
|
|
257
|
+
title: navigationItem.label,
|
|
258
|
+
permalink: navigationItem.link.permalink,
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
throw new Error('unexpected category link type');
|
|
271
262
|
}
|
|
263
|
+
throw new Error('unexpected navigation item');
|
|
272
264
|
}
|
|
273
265
|
exports.toNavigationLink = toNavigationLink;
|
|
@@ -10,7 +10,8 @@ exports.validateCategoryMetadataFile = exports.validateSidebars = void 0;
|
|
|
10
10
|
const utils_validation_1 = require("@docusaurus/utils-validation");
|
|
11
11
|
const utils_1 = require("./utils");
|
|
12
12
|
// NOTE: we don't add any default values during validation on purpose!
|
|
13
|
-
// Config types are exposed to users for typechecking and we use the same type
|
|
13
|
+
// Config types are exposed to users for typechecking and we use the same type
|
|
14
|
+
// in normalization
|
|
14
15
|
const sidebarItemBaseSchema = utils_validation_1.Joi.object({
|
|
15
16
|
className: utils_validation_1.Joi.string(),
|
|
16
17
|
customProps: utils_validation_1.Joi.object().unknown(),
|
|
@@ -19,7 +20,7 @@ const sidebarItemAutogeneratedSchema = sidebarItemBaseSchema.append({
|
|
|
19
20
|
type: 'autogenerated',
|
|
20
21
|
dirName: utils_validation_1.Joi.string()
|
|
21
22
|
.required()
|
|
22
|
-
.pattern(/^[^/](
|
|
23
|
+
.pattern(/^[^/](?:.*[^/])?$/)
|
|
23
24
|
.message('"dirName" must be a dir path relative to the docs folder root, and should not start or end with slash'),
|
|
24
25
|
});
|
|
25
26
|
const sidebarItemDocSchema = sidebarItemBaseSchema.append({
|
|
@@ -50,7 +51,8 @@ const sidebarItemCategoryLinkSchema = utils_validation_1.Joi.object()
|
|
|
50
51
|
then: utils_validation_1.Joi.object({
|
|
51
52
|
type: 'generated-index',
|
|
52
53
|
slug: utils_validation_1.Joi.string().optional(),
|
|
53
|
-
//
|
|
54
|
+
// This one is not in the user config, only in the normalized version
|
|
55
|
+
// permalink: Joi.string().optional(),
|
|
54
56
|
title: utils_validation_1.Joi.string().optional(),
|
|
55
57
|
description: utils_validation_1.Joi.string().optional(),
|
|
56
58
|
image: utils_validation_1.Joi.string().optional(),
|
|
@@ -107,7 +109,8 @@ function validateSidebarItem(item) {
|
|
|
107
109
|
return;
|
|
108
110
|
}
|
|
109
111
|
// TODO: remove once with proper Joi support
|
|
110
|
-
// Because we can't use Joi to validate nested items (see above), we do it
|
|
112
|
+
// Because we can't use Joi to validate nested items (see above), we do it
|
|
113
|
+
// manually
|
|
111
114
|
if ((0, utils_1.isCategoriesShorthand)(item)) {
|
|
112
115
|
Object.values(item).forEach((category) => category.forEach(validateSidebarItem));
|
|
113
116
|
}
|