@azerion/bunosaurus-plugin-content-docs 0.0.0-stage → 4.0.0
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/README.md +6 -2
- package/lib/categoryGeneratedIndex.d.ts +12 -0
- package/lib/categoryGeneratedIndex.js +36 -0
- package/lib/cli.d.ts +13 -0
- package/lib/cli.js +124 -0
- package/lib/client/doc.d.ts +29 -0
- package/lib/client/doc.js +47 -0
- package/lib/client/docSidebarItemsExpandedState.d.ts +30 -0
- package/lib/client/docSidebarItemsExpandedState.js +27 -0
- package/lib/client/docsClientUtils.d.ts +15 -0
- package/lib/client/docsClientUtils.js +86 -0
- package/lib/client/docsPreferredVersion.d.ts +29 -0
- package/lib/client/docsPreferredVersion.js +124 -0
- package/lib/client/docsSearch.d.ts +19 -0
- package/lib/client/docsSearch.js +39 -0
- package/lib/client/docsSidebar.d.ts +25 -0
- package/lib/client/docsSidebar.js +29 -0
- package/lib/client/docsUtils.d.ts +112 -0
- package/lib/client/docsUtils.js +299 -0
- package/lib/client/docsVersion.d.ts +19 -0
- package/lib/client/docsVersion.js +25 -0
- package/lib/client/index.d.ts +91 -0
- package/lib/client/index.js +83 -0
- package/lib/client/structuredDataUtils.d.ts +11 -0
- package/lib/client/structuredDataUtils.js +35 -0
- package/lib/constants.d.ts +14 -0
- package/lib/constants.js +17 -0
- package/lib/contentHelpers.d.ts +12 -0
- package/lib/contentHelpers.js +31 -0
- package/lib/docs.d.ts +48 -0
- package/lib/docs.js +252 -0
- package/lib/frontMatter.d.ts +10 -0
- package/lib/frontMatter.js +46 -0
- package/lib/globalData.d.ts +9 -0
- package/lib/globalData.js +59 -0
- package/lib/index.d.ts +10 -0
- package/lib/index.js +198 -0
- package/lib/numberPrefix.d.ts +11 -0
- package/lib/numberPrefix.js +50 -0
- package/lib/options.d.ts +10 -0
- package/lib/options.js +138 -0
- package/lib/props.d.ts +21 -0
- package/lib/props.js +156 -0
- package/lib/routes.d.ts +22 -0
- package/lib/routes.js +184 -0
- package/lib/server-export.d.ts +9 -0
- package/lib/server-export.js +25 -0
- package/lib/sidebars/generator.d.ts +10 -0
- package/lib/sidebars/generator.js +217 -0
- package/lib/sidebars/index.d.ts +13 -0
- package/lib/sidebars/index.js +99 -0
- package/lib/sidebars/normalization.d.ts +13 -0
- package/lib/sidebars/normalization.js +58 -0
- package/lib/sidebars/postProcessor.d.ts +11 -0
- package/lib/sidebars/postProcessor.js +82 -0
- package/lib/sidebars/processor.d.ts +10 -0
- package/lib/sidebars/processor.js +77 -0
- package/lib/sidebars/types.d.ts +192 -0
- package/lib/sidebars/types.js +8 -0
- package/lib/sidebars/utils.d.ts +69 -0
- package/lib/sidebars/utils.js +327 -0
- package/lib/sidebars/validation.d.ts +11 -0
- package/lib/sidebars/validation.js +152 -0
- package/lib/slug.d.ts +15 -0
- package/lib/slug.js +51 -0
- package/lib/translations.d.ts +10 -0
- package/lib/translations.js +243 -0
- package/lib/types.d.ts +27 -0
- package/lib/types.js +8 -0
- package/lib/versions/files.d.ts +54 -0
- package/lib/versions/files.js +152 -0
- package/lib/versions/loadVersion.d.ts +17 -0
- package/lib/versions/loadVersion.js +126 -0
- package/lib/versions/validation.d.ts +17 -0
- package/lib/versions/validation.js +70 -0
- package/lib/versions/version.d.ts +40 -0
- package/lib/versions/version.js +189 -0
- package/package.json +70 -4
- package/src/categoryGeneratedIndex.ts +60 -0
- package/src/cli.ts +180 -0
- package/src/client/doc.tsx +71 -0
- package/src/client/docSidebarItemsExpandedState.tsx +55 -0
- package/src/client/docsClientUtils.ts +140 -0
- package/src/client/docsPreferredVersion.tsx +245 -0
- package/src/client/docsSearch.test.ts +15 -0
- package/src/client/docsSearch.ts +57 -0
- package/src/client/docsSidebar.tsx +50 -0
- package/src/client/docsUtils.tsx +442 -0
- package/src/client/docsVersion.tsx +36 -0
- package/src/client/index.ts +211 -0
- package/src/client/structuredDataUtils.ts +54 -0
- package/src/constants.ts +15 -0
- package/src/contentHelpers.ts +34 -0
- package/src/docs.ts +402 -0
- package/src/frontMatter.ts +57 -0
- package/src/globalData.ts +79 -0
- package/src/index.ts +289 -0
- package/src/numberPrefix.ts +62 -0
- package/src/options.ts +185 -0
- package/src/plugin-content-docs.d.ts +667 -0
- package/src/props.ts +223 -0
- package/src/routes.ts +263 -0
- package/src/server-export.ts +26 -0
- package/src/sidebars/README.md +10 -0
- package/src/sidebars/generator.ts +307 -0
- package/src/sidebars/index.ts +130 -0
- package/src/sidebars/normalization.ts +91 -0
- package/src/sidebars/postProcessor.ts +115 -0
- package/src/sidebars/processor.ts +122 -0
- package/src/sidebars/types.ts +293 -0
- package/src/sidebars/utils.ts +529 -0
- package/src/sidebars/validation.ts +189 -0
- package/src/slug.ts +79 -0
- package/src/translations.ts +365 -0
- package/src/types.ts +34 -0
- package/src/versions/files.ts +240 -0
- package/src/versions/loadVersion.ts +185 -0
- package/src/versions/validation.ts +115 -0
- package/src/versions/version.ts +300 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.validateVersionName = validateVersionName;
|
|
10
|
+
exports.validateVersionNames = validateVersionNames;
|
|
11
|
+
exports.validateVersionsOptions = validateVersionsOptions;
|
|
12
|
+
const tslib_1 = require("tslib");
|
|
13
|
+
const lodash_1 = tslib_1.__importDefault(require("lodash"));
|
|
14
|
+
function validateVersionName(name) {
|
|
15
|
+
if (typeof name !== 'string') {
|
|
16
|
+
throw new Error(`Versions should be strings. Found type "${typeof name}" for version ${JSON.stringify(name)}.`);
|
|
17
|
+
}
|
|
18
|
+
if (!name.trim()) {
|
|
19
|
+
throw new Error(`Invalid version name "${name}": version name must contain at least one non-whitespace character.`);
|
|
20
|
+
}
|
|
21
|
+
const errors = [
|
|
22
|
+
[/[/\\]/, 'should not include slash (/) or backslash (\\)'],
|
|
23
|
+
[/.{33,}/, 'cannot be longer than 32 characters'],
|
|
24
|
+
// eslint-disable-next-line no-control-regex
|
|
25
|
+
[/[<>:"|?*\x00-\x1F]/, 'should be a valid file path'],
|
|
26
|
+
[/^\.\.?$/, 'should not be "." or ".."'],
|
|
27
|
+
];
|
|
28
|
+
errors.forEach(([pattern, message]) => {
|
|
29
|
+
if (pattern.test(name)) {
|
|
30
|
+
throw new Error(`Invalid version name "${name}": version name ${message}.`);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
function validateVersionNames(names) {
|
|
35
|
+
if (!Array.isArray(names)) {
|
|
36
|
+
throw new Error(`The versions file should contain an array of version names! Found content: ${JSON.stringify(names)}`);
|
|
37
|
+
}
|
|
38
|
+
names.forEach(validateVersionName);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* @throws Throws for one of the following invalid options:
|
|
42
|
+
* - `lastVersion` is non-existent
|
|
43
|
+
* - `versions` includes unknown keys
|
|
44
|
+
* - `onlyIncludeVersions` is empty, contains unknown names, or doesn't include
|
|
45
|
+
* `latestVersion` (if provided)
|
|
46
|
+
*/
|
|
47
|
+
function validateVersionsOptions(availableVersionNames, options) {
|
|
48
|
+
const availableVersionNamesMsg = `Available version names are: ${availableVersionNames.join(', ')}`;
|
|
49
|
+
if (options.lastVersion &&
|
|
50
|
+
!availableVersionNames.includes(options.lastVersion)) {
|
|
51
|
+
throw new Error(`Docs option lastVersion: ${options.lastVersion} is invalid. ${availableVersionNamesMsg}`);
|
|
52
|
+
}
|
|
53
|
+
const unknownVersionConfigNames = lodash_1.default.difference(Object.keys(options.versions), availableVersionNames);
|
|
54
|
+
if (unknownVersionConfigNames.length > 0) {
|
|
55
|
+
throw new Error(`Invalid docs option "versions": unknown versions (${unknownVersionConfigNames.join(',')}) found. ${availableVersionNamesMsg}`);
|
|
56
|
+
}
|
|
57
|
+
if (options.onlyIncludeVersions) {
|
|
58
|
+
if (options.onlyIncludeVersions.length === 0) {
|
|
59
|
+
throw new Error(`Invalid docs option "onlyIncludeVersions": an empty array is not allowed, at least one version is needed.`);
|
|
60
|
+
}
|
|
61
|
+
const unknownOnlyIncludeVersionNames = lodash_1.default.difference(options.onlyIncludeVersions, availableVersionNames);
|
|
62
|
+
if (unknownOnlyIncludeVersionNames.length > 0) {
|
|
63
|
+
throw new Error(`Invalid docs option "onlyIncludeVersions": unknown versions (${unknownOnlyIncludeVersionNames.join(',')}) found. ${availableVersionNamesMsg}`);
|
|
64
|
+
}
|
|
65
|
+
if (options.lastVersion &&
|
|
66
|
+
!options.onlyIncludeVersions.includes(options.lastVersion)) {
|
|
67
|
+
throw new Error(`Invalid docs option "lastVersion": if you use both the "onlyIncludeVersions" and "lastVersion" options, then "lastVersion" must be present in the provided "onlyIncludeVersions" array.`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
import type { FullVersion } from '../types';
|
|
8
|
+
import type { LoadContext } from '@docusaurus/types';
|
|
9
|
+
import type { LoadedVersion, PluginOptions, VersionBanner, VersionMetadata } from '@docusaurus/plugin-content-docs';
|
|
10
|
+
export type VersionContext = {
|
|
11
|
+
/** The version name to get banner of. */
|
|
12
|
+
versionName: string;
|
|
13
|
+
/** All versions, ordered from newest to oldest. */
|
|
14
|
+
versionNames: string[];
|
|
15
|
+
lastVersionName: string;
|
|
16
|
+
context: LoadContext;
|
|
17
|
+
options: PluginOptions;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* The default version banner depends on the version's relative position to the
|
|
21
|
+
* latest version. More recent ones are "unreleased", and older ones are
|
|
22
|
+
* "unmaintained".
|
|
23
|
+
*/
|
|
24
|
+
export declare function getDefaultVersionBanner({ versionName, versionNames, lastVersionName, }: VersionContext): VersionBanner | null;
|
|
25
|
+
export declare function getVersionBanner(context: VersionContext): VersionMetadata['banner'];
|
|
26
|
+
export declare function getVersionBadge({ versionName, versionNames, options, }: VersionContext): VersionMetadata['badge'];
|
|
27
|
+
export declare function getVersionNoIndex({ versionName, options, }: VersionContext): VersionMetadata['noIndex'];
|
|
28
|
+
/**
|
|
29
|
+
* Filter versions according to provided options (i.e. `onlyIncludeVersions`).
|
|
30
|
+
*
|
|
31
|
+
* Note: we preserve the order in which versions are provided; the order of the
|
|
32
|
+
* `onlyIncludeVersions` array does not matter
|
|
33
|
+
*/
|
|
34
|
+
export declare function filterVersions(versionNamesUnfiltered: string[], options: PluginOptions): string[];
|
|
35
|
+
export declare function readVersionsMetadata({ context, options, }: {
|
|
36
|
+
context: LoadContext;
|
|
37
|
+
options: PluginOptions;
|
|
38
|
+
}): Promise<VersionMetadata[]>;
|
|
39
|
+
export declare function toFullVersion(version: LoadedVersion): FullVersion;
|
|
40
|
+
export declare function getVersionFromSourceFilePath(filePath: string, versionsMetadata: VersionMetadata[]): VersionMetadata;
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.getDefaultVersionBanner = getDefaultVersionBanner;
|
|
10
|
+
exports.getVersionBanner = getVersionBanner;
|
|
11
|
+
exports.getVersionBadge = getVersionBadge;
|
|
12
|
+
exports.getVersionNoIndex = getVersionNoIndex;
|
|
13
|
+
exports.filterVersions = filterVersions;
|
|
14
|
+
exports.readVersionsMetadata = readVersionsMetadata;
|
|
15
|
+
exports.toFullVersion = toFullVersion;
|
|
16
|
+
exports.getVersionFromSourceFilePath = getVersionFromSourceFilePath;
|
|
17
|
+
const tslib_1 = require("tslib");
|
|
18
|
+
const node_path_1 = tslib_1.__importDefault(require("node:path"));
|
|
19
|
+
const utils_1 = require("@docusaurus/utils");
|
|
20
|
+
const constants_1 = require("../constants");
|
|
21
|
+
const validation_1 = require("./validation");
|
|
22
|
+
const files_1 = require("./files");
|
|
23
|
+
const utils_2 = require("../sidebars/utils");
|
|
24
|
+
const categoryGeneratedIndex_1 = require("../categoryGeneratedIndex");
|
|
25
|
+
function getVersionEditUrls({ contentPath, contentPathLocalized, context, options, }) {
|
|
26
|
+
// If the user is using the functional form of editUrl,
|
|
27
|
+
// she has total freedom and we can't compute a "version edit url"
|
|
28
|
+
if (!options.editUrl || typeof options.editUrl === 'function') {
|
|
29
|
+
return { editUrl: undefined, editUrlLocalized: undefined };
|
|
30
|
+
}
|
|
31
|
+
// Intermediate var just to please TS not narrowing to "string"
|
|
32
|
+
const editUrlOption = options.editUrl;
|
|
33
|
+
const getEditUrl = () => {
|
|
34
|
+
const editDirPath = options.editCurrentVersion ? options.path : contentPath;
|
|
35
|
+
return (0, utils_1.normalizeUrl)([
|
|
36
|
+
editUrlOption,
|
|
37
|
+
(0, utils_1.posixPath)(node_path_1.default.relative(context.siteDir, node_path_1.default.resolve(context.siteDir, editDirPath))),
|
|
38
|
+
]);
|
|
39
|
+
};
|
|
40
|
+
const getEditUrlLocalized = () => {
|
|
41
|
+
if (!contentPathLocalized) {
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
const editDirPathLocalized = options.editCurrentVersion
|
|
45
|
+
? (0, files_1.getDocsDirPathLocalized)({
|
|
46
|
+
localizationDir: context.localizationDir,
|
|
47
|
+
versionName: constants_1.CURRENT_VERSION_NAME,
|
|
48
|
+
pluginId: options.id,
|
|
49
|
+
})
|
|
50
|
+
: contentPathLocalized;
|
|
51
|
+
return (0, utils_1.normalizeUrl)([
|
|
52
|
+
editUrlOption,
|
|
53
|
+
(0, utils_1.posixPath)(node_path_1.default.relative(context.siteDir, node_path_1.default.resolve(context.siteDir, editDirPathLocalized))),
|
|
54
|
+
]);
|
|
55
|
+
};
|
|
56
|
+
return { editUrl: getEditUrl(), editUrlLocalized: getEditUrlLocalized() };
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* The default version banner depends on the version's relative position to the
|
|
60
|
+
* latest version. More recent ones are "unreleased", and older ones are
|
|
61
|
+
* "unmaintained".
|
|
62
|
+
*/
|
|
63
|
+
function getDefaultVersionBanner({ versionName, versionNames, lastVersionName, }) {
|
|
64
|
+
// Current version: good, no banner
|
|
65
|
+
if (versionName === lastVersionName) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
// Upcoming versions: unreleased banner
|
|
69
|
+
if (versionNames.indexOf(versionName) < versionNames.indexOf(lastVersionName)) {
|
|
70
|
+
return 'unreleased';
|
|
71
|
+
}
|
|
72
|
+
// Older versions: display unmaintained banner
|
|
73
|
+
return 'unmaintained';
|
|
74
|
+
}
|
|
75
|
+
function getVersionBanner(context) {
|
|
76
|
+
const { versionName, options } = context;
|
|
77
|
+
const versionBannerOption = options.versions[versionName]?.banner;
|
|
78
|
+
if (versionBannerOption) {
|
|
79
|
+
return versionBannerOption === 'none' ? null : versionBannerOption;
|
|
80
|
+
}
|
|
81
|
+
return getDefaultVersionBanner(context);
|
|
82
|
+
}
|
|
83
|
+
function getVersionBadge({ versionName, versionNames, options, }) {
|
|
84
|
+
// If site is not versioned or only one version is included
|
|
85
|
+
// we don't show the version badge by default
|
|
86
|
+
// See https://github.com/facebook/docusaurus/issues/3362
|
|
87
|
+
const defaultVersionBadge = versionNames.length !== 1;
|
|
88
|
+
return options.versions[versionName]?.badge ?? defaultVersionBadge;
|
|
89
|
+
}
|
|
90
|
+
function getVersionNoIndex({ versionName, options, }) {
|
|
91
|
+
return options.versions[versionName]?.noIndex ?? false;
|
|
92
|
+
}
|
|
93
|
+
function getVersionClassName({ versionName, options, }) {
|
|
94
|
+
const defaultVersionClassName = `docs-version-${versionName}`;
|
|
95
|
+
return options.versions[versionName]?.className ?? defaultVersionClassName;
|
|
96
|
+
}
|
|
97
|
+
function getVersionLabel({ versionName, options, }) {
|
|
98
|
+
const defaultVersionLabel = versionName === constants_1.CURRENT_VERSION_NAME ? 'Next' : versionName;
|
|
99
|
+
return options.versions[versionName]?.label ?? defaultVersionLabel;
|
|
100
|
+
}
|
|
101
|
+
function getVersionPathPart({ versionName, options, lastVersionName, }) {
|
|
102
|
+
function getDefaultVersionPathPart() {
|
|
103
|
+
if (versionName === lastVersionName) {
|
|
104
|
+
return '';
|
|
105
|
+
}
|
|
106
|
+
return versionName === constants_1.CURRENT_VERSION_NAME ? 'next' : versionName;
|
|
107
|
+
}
|
|
108
|
+
return options.versions[versionName]?.path ?? getDefaultVersionPathPart();
|
|
109
|
+
}
|
|
110
|
+
async function createVersionMetadata(context) {
|
|
111
|
+
const { versionName, lastVersionName, options, context: loadContext } = context;
|
|
112
|
+
const { sidebarFilePath, contentPath, contentPathLocalized } = await (0, files_1.getVersionMetadataPaths)(context);
|
|
113
|
+
const versionPathPart = getVersionPathPart(context);
|
|
114
|
+
const routePath = (0, utils_1.normalizeUrl)([
|
|
115
|
+
loadContext.baseUrl,
|
|
116
|
+
options.routeBasePath,
|
|
117
|
+
versionPathPart,
|
|
118
|
+
]);
|
|
119
|
+
const versionEditUrls = getVersionEditUrls({
|
|
120
|
+
contentPath,
|
|
121
|
+
contentPathLocalized,
|
|
122
|
+
context: loadContext,
|
|
123
|
+
options,
|
|
124
|
+
});
|
|
125
|
+
return {
|
|
126
|
+
versionName,
|
|
127
|
+
label: getVersionLabel(context),
|
|
128
|
+
banner: getVersionBanner(context),
|
|
129
|
+
badge: getVersionBadge(context),
|
|
130
|
+
noIndex: getVersionNoIndex(context),
|
|
131
|
+
className: getVersionClassName(context),
|
|
132
|
+
path: routePath,
|
|
133
|
+
tagsPath: (0, utils_1.normalizeUrl)([routePath, options.tagsBasePath]),
|
|
134
|
+
...versionEditUrls,
|
|
135
|
+
isLast: versionName === lastVersionName,
|
|
136
|
+
routePriority: versionPathPart === '' ? -1 : undefined,
|
|
137
|
+
sidebarFilePath,
|
|
138
|
+
contentPath,
|
|
139
|
+
contentPathLocalized,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Filter versions according to provided options (i.e. `onlyIncludeVersions`).
|
|
144
|
+
*
|
|
145
|
+
* Note: we preserve the order in which versions are provided; the order of the
|
|
146
|
+
* `onlyIncludeVersions` array does not matter
|
|
147
|
+
*/
|
|
148
|
+
function filterVersions(versionNamesUnfiltered, options) {
|
|
149
|
+
if (options.onlyIncludeVersions) {
|
|
150
|
+
return versionNamesUnfiltered.filter((name) => options.onlyIncludeVersions.includes(name));
|
|
151
|
+
}
|
|
152
|
+
return versionNamesUnfiltered;
|
|
153
|
+
}
|
|
154
|
+
function getLastVersionName({ versionNames, options, }) {
|
|
155
|
+
return (options.lastVersion ??
|
|
156
|
+
versionNames.find((name) => name !== constants_1.CURRENT_VERSION_NAME) ??
|
|
157
|
+
constants_1.CURRENT_VERSION_NAME);
|
|
158
|
+
}
|
|
159
|
+
async function readVersionsMetadata({ context, options, }) {
|
|
160
|
+
const allVersionNames = await (0, files_1.readVersionNames)(context.siteDir, options);
|
|
161
|
+
(0, validation_1.validateVersionsOptions)(allVersionNames, options);
|
|
162
|
+
const versionNames = filterVersions(allVersionNames, options);
|
|
163
|
+
const lastVersionName = getLastVersionName({ versionNames, options });
|
|
164
|
+
return Promise.all(versionNames.map((versionName) => createVersionMetadata({
|
|
165
|
+
versionName,
|
|
166
|
+
versionNames,
|
|
167
|
+
lastVersionName,
|
|
168
|
+
context,
|
|
169
|
+
options,
|
|
170
|
+
})));
|
|
171
|
+
}
|
|
172
|
+
function toFullVersion(version) {
|
|
173
|
+
const sidebarsUtils = (0, utils_2.createSidebarsUtils)(version.sidebars);
|
|
174
|
+
return {
|
|
175
|
+
...version,
|
|
176
|
+
sidebarsUtils,
|
|
177
|
+
categoryGeneratedIndices: (0, categoryGeneratedIndex_1.getCategoryGeneratedIndexMetadataList)({
|
|
178
|
+
docs: version.docs,
|
|
179
|
+
sidebarsUtils,
|
|
180
|
+
}),
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
function getVersionFromSourceFilePath(filePath, versionsMetadata) {
|
|
184
|
+
const versionFound = versionsMetadata.find((version) => (0, utils_1.getContentPathList)(version).some((docsDirPath) => filePath.startsWith(docsDirPath)));
|
|
185
|
+
if (!versionFound) {
|
|
186
|
+
throw new Error(`Unexpected error: file at "${filePath}" does not belong to any docs version!`);
|
|
187
|
+
}
|
|
188
|
+
return versionFound;
|
|
189
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,72 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@azerion/bunosaurus-plugin-content-docs",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "4.0.0",
|
|
4
|
+
"description": "Docs plugin for Docusaurus.",
|
|
5
|
+
"main": "lib/index.js",
|
|
6
|
+
"sideEffects": false,
|
|
7
|
+
"exports": {
|
|
8
|
+
"./lib/*": "./lib/*",
|
|
9
|
+
"./src/*": "./src/*",
|
|
10
|
+
"./client": {
|
|
11
|
+
"type": "./lib/client/index.d.ts",
|
|
12
|
+
"default": "./lib/client/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./server": {
|
|
15
|
+
"type": "./lib/server-export.d.ts",
|
|
16
|
+
"default": "./lib/server-export.js"
|
|
17
|
+
},
|
|
18
|
+
".": {
|
|
19
|
+
"types": "./src/plugin-content-docs.d.ts",
|
|
20
|
+
"default": "./lib/index.js"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"types": "src/plugin-content-docs.d.ts",
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "tsc --build",
|
|
26
|
+
"watch": "tsc --build --watch"
|
|
27
|
+
},
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"access": "public"
|
|
30
|
+
},
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "https://github.com/azerion/bunosaurus.git",
|
|
34
|
+
"directory": "packages/docusaurus-plugin-content-docs"
|
|
35
|
+
},
|
|
36
|
+
"license": "MIT",
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@docusaurus/core": "npm:@azerion/bunosaurus-core@4.0.0",
|
|
39
|
+
"@docusaurus/fs": "npm:@azerion/bunosaurus-fs@4.0.0",
|
|
40
|
+
"@docusaurus/glob": "npm:@azerion/bunosaurus-glob@4.0.0",
|
|
41
|
+
"@docusaurus/logger": "npm:@azerion/bunosaurus-logger@4.0.0",
|
|
42
|
+
"@docusaurus/mdx-loader": "npm:@azerion/bunosaurus-mdx-loader@4.0.0",
|
|
43
|
+
"@docusaurus/module-type-aliases": "npm:@azerion/bunosaurus-module-type-aliases@4.0.0",
|
|
44
|
+
"@docusaurus/theme-common": "npm:@azerion/bunosaurus-theme-common@4.0.0",
|
|
45
|
+
"@docusaurus/types": "npm:@azerion/bunosaurus-types@4.0.0",
|
|
46
|
+
"@docusaurus/utils": "npm:@azerion/bunosaurus-utils@4.0.0",
|
|
47
|
+
"@docusaurus/utils-common": "npm:@azerion/bunosaurus-utils-common@4.0.0",
|
|
48
|
+
"@docusaurus/utils-validation": "npm:@azerion/bunosaurus-utils-validation@4.0.0",
|
|
49
|
+
"@types/react-router-config": "^5.0.11",
|
|
50
|
+
"combine-promises": "^1.2.0",
|
|
51
|
+
"js-yaml": "^5.4.1",
|
|
52
|
+
"lodash": "^4.18.1",
|
|
53
|
+
"schema-dts": "^1.1.5",
|
|
54
|
+
"tslib": "^2.8.1",
|
|
55
|
+
"utility-types": "^3.11.0"
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"@total-typescript/shoehorn": "^0.1.2",
|
|
59
|
+
"@types/picomatch": "^2.3.4",
|
|
60
|
+
"commander": "^15.0.0",
|
|
61
|
+
"picomatch": "^2.3.2",
|
|
62
|
+
"react-router-dom": "^5.3.4",
|
|
63
|
+
"webpack": "^5.111.0"
|
|
64
|
+
},
|
|
65
|
+
"peerDependencies": {
|
|
66
|
+
"react": "^19.3.0",
|
|
67
|
+
"react-dom": "^19.3.0"
|
|
68
|
+
},
|
|
69
|
+
"engines": {
|
|
70
|
+
"bun": ">=1.4.1"
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {type SidebarsUtils, toNavigationLink} from './sidebars/utils';
|
|
9
|
+
import {createDocsByIdIndex} from './docs';
|
|
10
|
+
import type {
|
|
11
|
+
CategoryGeneratedIndexMetadata,
|
|
12
|
+
DocMetadataBase,
|
|
13
|
+
} from '@docusaurus/plugin-content-docs';
|
|
14
|
+
import type {SidebarItemCategoryWithGeneratedIndex} from './sidebars/types';
|
|
15
|
+
|
|
16
|
+
function getCategoryGeneratedIndexMetadata({
|
|
17
|
+
category,
|
|
18
|
+
sidebarsUtils,
|
|
19
|
+
docsById,
|
|
20
|
+
}: {
|
|
21
|
+
category: SidebarItemCategoryWithGeneratedIndex;
|
|
22
|
+
sidebarsUtils: SidebarsUtils;
|
|
23
|
+
docsById: {[docId: string]: DocMetadataBase};
|
|
24
|
+
}): CategoryGeneratedIndexMetadata {
|
|
25
|
+
const {sidebarName, previous, next} =
|
|
26
|
+
sidebarsUtils.getCategoryGeneratedIndexNavigation(category.link.permalink);
|
|
27
|
+
return {
|
|
28
|
+
title: category.link.title ?? category.label,
|
|
29
|
+
description: category.link.description,
|
|
30
|
+
image: category.link.image,
|
|
31
|
+
keywords: category.link.keywords,
|
|
32
|
+
slug: category.link.slug,
|
|
33
|
+
permalink: category.link.permalink,
|
|
34
|
+
sidebar: sidebarName!,
|
|
35
|
+
navigation: {
|
|
36
|
+
previous: toNavigationLink(previous, docsById),
|
|
37
|
+
next: toNavigationLink(next, docsById),
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function getCategoryGeneratedIndexMetadataList({
|
|
43
|
+
docs,
|
|
44
|
+
sidebarsUtils,
|
|
45
|
+
}: {
|
|
46
|
+
sidebarsUtils: SidebarsUtils;
|
|
47
|
+
docs: DocMetadataBase[];
|
|
48
|
+
}): CategoryGeneratedIndexMetadata[] {
|
|
49
|
+
const docsById = createDocsByIdIndex(docs);
|
|
50
|
+
|
|
51
|
+
const categoryGeneratedIndexItems =
|
|
52
|
+
sidebarsUtils.getCategoryGeneratedIndexList();
|
|
53
|
+
return categoryGeneratedIndexItems.map((category) =>
|
|
54
|
+
getCategoryGeneratedIndexMetadata({
|
|
55
|
+
category,
|
|
56
|
+
sidebarsUtils,
|
|
57
|
+
docsById,
|
|
58
|
+
}),
|
|
59
|
+
);
|
|
60
|
+
}
|
package/src/cli.ts
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
import logger from '@docusaurus/logger';
|
|
10
|
+
import {DEFAULT_PLUGIN_ID, getLocaleConfig} from '@docusaurus/utils';
|
|
11
|
+
import {fs, pathExists, outputFile} from '@docusaurus/fs';
|
|
12
|
+
import {
|
|
13
|
+
getVersionsFilePath,
|
|
14
|
+
getVersionDocsDirPath,
|
|
15
|
+
getVersionSidebarsPath,
|
|
16
|
+
getDocsDirPathLocalized,
|
|
17
|
+
getPluginDirPathLocalized,
|
|
18
|
+
readVersionsFile,
|
|
19
|
+
} from './versions/files';
|
|
20
|
+
import {validateVersionName} from './versions/validation';
|
|
21
|
+
import {loadSidebarsFile} from './sidebars';
|
|
22
|
+
import {CURRENT_VERSION_NAME} from './constants';
|
|
23
|
+
import type {PluginOptions} from '@docusaurus/plugin-content-docs';
|
|
24
|
+
import type {LoadContext} from '@docusaurus/types';
|
|
25
|
+
|
|
26
|
+
async function createVersionedSidebarFile({
|
|
27
|
+
siteDir,
|
|
28
|
+
pluginId,
|
|
29
|
+
sidebarPath,
|
|
30
|
+
version,
|
|
31
|
+
}: {
|
|
32
|
+
siteDir: string;
|
|
33
|
+
pluginId: string;
|
|
34
|
+
sidebarPath: string | false | undefined;
|
|
35
|
+
version: string;
|
|
36
|
+
}) {
|
|
37
|
+
// Load current sidebar and create a new versioned sidebars file (if needed).
|
|
38
|
+
// Note: we don't need the sidebars file to be normalized: it's ok to let
|
|
39
|
+
// plugin option changes to impact older, versioned sidebars
|
|
40
|
+
// We don't validate here, assuming the user has already built the version
|
|
41
|
+
const sidebars = await loadSidebarsFile(sidebarPath);
|
|
42
|
+
|
|
43
|
+
// Do not create a useless versioned sidebars file if sidebars file is empty
|
|
44
|
+
// or sidebars are disabled/false)
|
|
45
|
+
const shouldCreateVersionedSidebarFile = Object.keys(sidebars).length > 0;
|
|
46
|
+
|
|
47
|
+
if (shouldCreateVersionedSidebarFile) {
|
|
48
|
+
await outputFile(
|
|
49
|
+
getVersionSidebarsPath(siteDir, pluginId, version),
|
|
50
|
+
`${JSON.stringify(sidebars, null, 2)}\n`,
|
|
51
|
+
'utf8',
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Tests depend on non-default export for mocking.
|
|
57
|
+
async function cliDocsVersionCommand(
|
|
58
|
+
version: unknown,
|
|
59
|
+
{id: pluginId, path: docsPath, sidebarPath}: PluginOptions,
|
|
60
|
+
{siteDir, i18n}: LoadContext,
|
|
61
|
+
): Promise<void> {
|
|
62
|
+
// It wouldn't be very user-friendly to show a [default] log prefix,
|
|
63
|
+
// so we use [docs] instead of [default]
|
|
64
|
+
const pluginIdLogPrefix =
|
|
65
|
+
pluginId === DEFAULT_PLUGIN_ID ? '[docs]' : `[${pluginId}]`;
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
validateVersionName(version);
|
|
69
|
+
} catch (err) {
|
|
70
|
+
logger.info`${pluginIdLogPrefix}: Invalid version name provided. Try something like: 1.0.0`;
|
|
71
|
+
throw err;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const versions = (await readVersionsFile(siteDir, pluginId)) ?? [];
|
|
75
|
+
|
|
76
|
+
// Check if version already exists.
|
|
77
|
+
if (versions.includes(version)) {
|
|
78
|
+
throw new Error(
|
|
79
|
+
`${pluginIdLogPrefix}: this version already exists! Use a version tag that does not already exist.`,
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (i18n.locales.length > 1) {
|
|
84
|
+
logger.info`Versioned docs will be created for the following locales: name=${i18n.locales}`;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
await Promise.all(
|
|
88
|
+
i18n.locales.map(async (locale) => {
|
|
89
|
+
const localizationDir = path.resolve(
|
|
90
|
+
siteDir,
|
|
91
|
+
i18n.path,
|
|
92
|
+
getLocaleConfig(i18n, locale).path,
|
|
93
|
+
);
|
|
94
|
+
// Copy docs files.
|
|
95
|
+
const docsDir =
|
|
96
|
+
locale === i18n.defaultLocale
|
|
97
|
+
? path.resolve(siteDir, docsPath)
|
|
98
|
+
: getDocsDirPathLocalized({
|
|
99
|
+
localizationDir,
|
|
100
|
+
pluginId,
|
|
101
|
+
versionName: CURRENT_VERSION_NAME,
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
if (
|
|
105
|
+
!(await pathExists(docsDir)) ||
|
|
106
|
+
(await fs.readdir(docsDir)).length === 0
|
|
107
|
+
) {
|
|
108
|
+
if (locale === i18n.defaultLocale) {
|
|
109
|
+
throw new Error(
|
|
110
|
+
logger.interpolate`${pluginIdLogPrefix}: no docs found in path=${docsDir}.`,
|
|
111
|
+
);
|
|
112
|
+
} else {
|
|
113
|
+
logger.warn`${pluginIdLogPrefix}: no docs found in path=${docsDir}. Skipping.`;
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const newVersionDir =
|
|
119
|
+
locale === i18n.defaultLocale
|
|
120
|
+
? getVersionDocsDirPath(siteDir, pluginId, version)
|
|
121
|
+
: getDocsDirPathLocalized({
|
|
122
|
+
localizationDir,
|
|
123
|
+
pluginId,
|
|
124
|
+
versionName: version,
|
|
125
|
+
});
|
|
126
|
+
// verbatimSymlinks: keep relative symlinks relative
|
|
127
|
+
await fs.cp(docsDir, newVersionDir, {
|
|
128
|
+
recursive: true,
|
|
129
|
+
verbatimSymlinks: true,
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// Copy version JSON translation file for this locale
|
|
133
|
+
// i18n/<l>/docusaurus-plugin-content-docs/current.json => version-v1.json
|
|
134
|
+
// See https://docusaurus.io/docs/next/api/plugins/@docusaurus/plugin-content-docs#translation-files-location
|
|
135
|
+
if (locale !== i18n.defaultLocale) {
|
|
136
|
+
const dir = getPluginDirPathLocalized({
|
|
137
|
+
localizationDir,
|
|
138
|
+
pluginId,
|
|
139
|
+
});
|
|
140
|
+
const sourceFile = path.join(dir, 'current.json');
|
|
141
|
+
const dest = path.join(dir, `version-${version}.json`);
|
|
142
|
+
if (await pathExists(sourceFile)) {
|
|
143
|
+
await fs.cp(sourceFile, dest, {verbatimSymlinks: true});
|
|
144
|
+
} else {
|
|
145
|
+
logger.warn`${pluginIdLogPrefix}: i18n translation file does not exist in path=${sourceFile}. Skipping.`;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}),
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
await createVersionedSidebarFile({
|
|
152
|
+
siteDir,
|
|
153
|
+
pluginId,
|
|
154
|
+
version,
|
|
155
|
+
sidebarPath,
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// Update versions.json file.
|
|
159
|
+
versions.unshift(version);
|
|
160
|
+
await outputFile(
|
|
161
|
+
getVersionsFilePath(siteDir, pluginId),
|
|
162
|
+
`${JSON.stringify(versions, null, 2)}\n`,
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
logger.success`name=${pluginIdLogPrefix}: version name=${version} created!`;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// TODO try to remove this workaround
|
|
169
|
+
// Why use a default export instead of named exports here?
|
|
170
|
+
// This is only to make Jest mocking happy
|
|
171
|
+
// After upgrading Jest/SWC we got this weird mocking error in extendCli tests
|
|
172
|
+
// "spyOn: Cannot redefine property cliDocsVersionCommand"
|
|
173
|
+
// I tried various workarounds, and it's the only one that worked :/
|
|
174
|
+
// See also:
|
|
175
|
+
// - https://pyk.sh/fixing-typeerror-cannot-redefine-property-x-error-in-jest-tests#heading-solution-2-using-barrel-imports
|
|
176
|
+
// - https://github.com/aelbore/esbuild-jest/issues/26
|
|
177
|
+
// - https://stackoverflow.com/questions/67872622/jest-spyon-not-working-on-index-file-cannot-redefine-property/69951703#69951703
|
|
178
|
+
export default {
|
|
179
|
+
cliDocsVersionCommand,
|
|
180
|
+
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import React, {useMemo, type ReactNode, useContext} from 'react';
|
|
9
|
+
import {ReactContextError} from '@docusaurus/theme-common';
|
|
10
|
+
import type {PropDocContent} from '@docusaurus/plugin-content-docs';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* The React context value returned by the `useDoc()` hook.
|
|
14
|
+
* It contains useful data related to the currently browsed doc.
|
|
15
|
+
*/
|
|
16
|
+
export type DocContextValue = Pick<
|
|
17
|
+
PropDocContent,
|
|
18
|
+
'metadata' | 'frontMatter' | 'toc' | 'assets' | 'contentTitle'
|
|
19
|
+
>;
|
|
20
|
+
|
|
21
|
+
const Context = React.createContext<DocContextValue | null>(null);
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Note: we don't use `PropDoc` as context value on purpose. Metadata is
|
|
25
|
+
* currently stored inside the MDX component, but we may want to change that in
|
|
26
|
+
* the future. This layer is a good opportunity to decouple storage from
|
|
27
|
+
* consuming API, potentially allowing us to provide metadata as both props and
|
|
28
|
+
* route context without duplicating the chunks in the future.
|
|
29
|
+
*/
|
|
30
|
+
function useContextValue(content: PropDocContent): DocContextValue {
|
|
31
|
+
return useMemo(
|
|
32
|
+
() => ({
|
|
33
|
+
metadata: content.metadata,
|
|
34
|
+
frontMatter: content.frontMatter,
|
|
35
|
+
assets: content.assets,
|
|
36
|
+
contentTitle: content.contentTitle,
|
|
37
|
+
toc: content.toc,
|
|
38
|
+
}),
|
|
39
|
+
[content],
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* This is a very thin layer around the `content` received from the MDX loader.
|
|
45
|
+
* It provides metadata about the doc to the children tree.
|
|
46
|
+
*/
|
|
47
|
+
export function DocProvider({
|
|
48
|
+
children,
|
|
49
|
+
content,
|
|
50
|
+
}: {
|
|
51
|
+
children: ReactNode;
|
|
52
|
+
content: PropDocContent;
|
|
53
|
+
}): ReactNode {
|
|
54
|
+
const contextValue = useContextValue(content);
|
|
55
|
+
return <Context value={contextValue}>{children}</Context>;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Returns the data of the currently browsed doc. Gives access to the doc's MDX
|
|
60
|
+
* Component, front matter, metadata, TOC, etc. When swizzling a low-level
|
|
61
|
+
* component (e.g. the "Edit this page" link) and you need some extra metadata,
|
|
62
|
+
* you don't have to drill the props all the way through the component tree:
|
|
63
|
+
* simply use this hook instead.
|
|
64
|
+
*/
|
|
65
|
+
export function useDoc(): DocContextValue {
|
|
66
|
+
const doc = useContext(Context);
|
|
67
|
+
if (doc === null) {
|
|
68
|
+
throw new ReactContextError('DocProvider');
|
|
69
|
+
}
|
|
70
|
+
return doc;
|
|
71
|
+
}
|