@azerion/bunosaurus-plugin-content-docs 0.0.0-stage → 4.0.0-canary-6927
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
package/README.md
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
-
#
|
|
1
|
+
# `@docusaurus/plugin-content-docs`
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Docs plugin for Docusaurus.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
See [plugin-content-docs documentation](https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-content-docs).
|
|
@@ -0,0 +1,12 @@
|
|
|
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 SidebarsUtils } from './sidebars/utils';
|
|
8
|
+
import type { CategoryGeneratedIndexMetadata, DocMetadataBase } from '@docusaurus/plugin-content-docs';
|
|
9
|
+
export declare function getCategoryGeneratedIndexMetadataList({ docs, sidebarsUtils, }: {
|
|
10
|
+
sidebarsUtils: SidebarsUtils;
|
|
11
|
+
docs: DocMetadataBase[];
|
|
12
|
+
}): CategoryGeneratedIndexMetadata[];
|
|
@@ -0,0 +1,36 @@
|
|
|
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.getCategoryGeneratedIndexMetadataList = getCategoryGeneratedIndexMetadataList;
|
|
10
|
+
const utils_1 = require("./sidebars/utils");
|
|
11
|
+
const docs_1 = require("./docs");
|
|
12
|
+
function getCategoryGeneratedIndexMetadata({ category, sidebarsUtils, docsById, }) {
|
|
13
|
+
const { sidebarName, previous, next } = sidebarsUtils.getCategoryGeneratedIndexNavigation(category.link.permalink);
|
|
14
|
+
return {
|
|
15
|
+
title: category.link.title ?? category.label,
|
|
16
|
+
description: category.link.description,
|
|
17
|
+
image: category.link.image,
|
|
18
|
+
keywords: category.link.keywords,
|
|
19
|
+
slug: category.link.slug,
|
|
20
|
+
permalink: category.link.permalink,
|
|
21
|
+
sidebar: sidebarName,
|
|
22
|
+
navigation: {
|
|
23
|
+
previous: (0, utils_1.toNavigationLink)(previous, docsById),
|
|
24
|
+
next: (0, utils_1.toNavigationLink)(next, docsById),
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function getCategoryGeneratedIndexMetadataList({ docs, sidebarsUtils, }) {
|
|
29
|
+
const docsById = (0, docs_1.createDocsByIdIndex)(docs);
|
|
30
|
+
const categoryGeneratedIndexItems = sidebarsUtils.getCategoryGeneratedIndexList();
|
|
31
|
+
return categoryGeneratedIndexItems.map((category) => getCategoryGeneratedIndexMetadata({
|
|
32
|
+
category,
|
|
33
|
+
sidebarsUtils,
|
|
34
|
+
docsById,
|
|
35
|
+
}));
|
|
36
|
+
}
|
package/lib/cli.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
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 { PluginOptions } from '@docusaurus/plugin-content-docs';
|
|
8
|
+
import type { LoadContext } from '@docusaurus/types';
|
|
9
|
+
declare function cliDocsVersionCommand(version: unknown, { id: pluginId, path: docsPath, sidebarPath }: PluginOptions, { siteDir, i18n }: LoadContext): Promise<void>;
|
|
10
|
+
declare const _default: {
|
|
11
|
+
cliDocsVersionCommand: typeof cliDocsVersionCommand;
|
|
12
|
+
};
|
|
13
|
+
export default _default;
|
package/lib/cli.js
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
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
|
+
const tslib_1 = require("tslib");
|
|
10
|
+
const node_path_1 = tslib_1.__importDefault(require("node:path"));
|
|
11
|
+
const logger_1 = tslib_1.__importDefault(require("@docusaurus/logger"));
|
|
12
|
+
const utils_1 = require("@docusaurus/utils");
|
|
13
|
+
const fs_1 = require("@docusaurus/fs");
|
|
14
|
+
const files_1 = require("./versions/files");
|
|
15
|
+
const validation_1 = require("./versions/validation");
|
|
16
|
+
const sidebars_1 = require("./sidebars");
|
|
17
|
+
const constants_1 = require("./constants");
|
|
18
|
+
async function createVersionedSidebarFile({ siteDir, pluginId, sidebarPath, version, }) {
|
|
19
|
+
// Load current sidebar and create a new versioned sidebars file (if needed).
|
|
20
|
+
// Note: we don't need the sidebars file to be normalized: it's ok to let
|
|
21
|
+
// plugin option changes to impact older, versioned sidebars
|
|
22
|
+
// We don't validate here, assuming the user has already built the version
|
|
23
|
+
const sidebars = await (0, sidebars_1.loadSidebarsFile)(sidebarPath);
|
|
24
|
+
// Do not create a useless versioned sidebars file if sidebars file is empty
|
|
25
|
+
// or sidebars are disabled/false)
|
|
26
|
+
const shouldCreateVersionedSidebarFile = Object.keys(sidebars).length > 0;
|
|
27
|
+
if (shouldCreateVersionedSidebarFile) {
|
|
28
|
+
await (0, fs_1.outputFile)((0, files_1.getVersionSidebarsPath)(siteDir, pluginId, version), `${JSON.stringify(sidebars, null, 2)}\n`, 'utf8');
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// Tests depend on non-default export for mocking.
|
|
32
|
+
async function cliDocsVersionCommand(version, { id: pluginId, path: docsPath, sidebarPath }, { siteDir, i18n }) {
|
|
33
|
+
// It wouldn't be very user-friendly to show a [default] log prefix,
|
|
34
|
+
// so we use [docs] instead of [default]
|
|
35
|
+
const pluginIdLogPrefix = pluginId === utils_1.DEFAULT_PLUGIN_ID ? '[docs]' : `[${pluginId}]`;
|
|
36
|
+
try {
|
|
37
|
+
(0, validation_1.validateVersionName)(version);
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
logger_1.default.info `${pluginIdLogPrefix}: Invalid version name provided. Try something like: 1.0.0`;
|
|
41
|
+
throw err;
|
|
42
|
+
}
|
|
43
|
+
const versions = (await (0, files_1.readVersionsFile)(siteDir, pluginId)) ?? [];
|
|
44
|
+
// Check if version already exists.
|
|
45
|
+
if (versions.includes(version)) {
|
|
46
|
+
throw new Error(`${pluginIdLogPrefix}: this version already exists! Use a version tag that does not already exist.`);
|
|
47
|
+
}
|
|
48
|
+
if (i18n.locales.length > 1) {
|
|
49
|
+
logger_1.default.info `Versioned docs will be created for the following locales: name=${i18n.locales}`;
|
|
50
|
+
}
|
|
51
|
+
await Promise.all(i18n.locales.map(async (locale) => {
|
|
52
|
+
const localizationDir = node_path_1.default.resolve(siteDir, i18n.path, (0, utils_1.getLocaleConfig)(i18n, locale).path);
|
|
53
|
+
// Copy docs files.
|
|
54
|
+
const docsDir = locale === i18n.defaultLocale
|
|
55
|
+
? node_path_1.default.resolve(siteDir, docsPath)
|
|
56
|
+
: (0, files_1.getDocsDirPathLocalized)({
|
|
57
|
+
localizationDir,
|
|
58
|
+
pluginId,
|
|
59
|
+
versionName: constants_1.CURRENT_VERSION_NAME,
|
|
60
|
+
});
|
|
61
|
+
if (!(await (0, fs_1.pathExists)(docsDir)) ||
|
|
62
|
+
(await fs_1.fs.readdir(docsDir)).length === 0) {
|
|
63
|
+
if (locale === i18n.defaultLocale) {
|
|
64
|
+
throw new Error(logger_1.default.interpolate `${pluginIdLogPrefix}: no docs found in path=${docsDir}.`);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
logger_1.default.warn `${pluginIdLogPrefix}: no docs found in path=${docsDir}. Skipping.`;
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const newVersionDir = locale === i18n.defaultLocale
|
|
72
|
+
? (0, files_1.getVersionDocsDirPath)(siteDir, pluginId, version)
|
|
73
|
+
: (0, files_1.getDocsDirPathLocalized)({
|
|
74
|
+
localizationDir,
|
|
75
|
+
pluginId,
|
|
76
|
+
versionName: version,
|
|
77
|
+
});
|
|
78
|
+
// verbatimSymlinks: keep relative symlinks relative
|
|
79
|
+
await fs_1.fs.cp(docsDir, newVersionDir, {
|
|
80
|
+
recursive: true,
|
|
81
|
+
verbatimSymlinks: true,
|
|
82
|
+
});
|
|
83
|
+
// Copy version JSON translation file for this locale
|
|
84
|
+
// i18n/<l>/docusaurus-plugin-content-docs/current.json => version-v1.json
|
|
85
|
+
// See https://docusaurus.io/docs/next/api/plugins/@docusaurus/plugin-content-docs#translation-files-location
|
|
86
|
+
if (locale !== i18n.defaultLocale) {
|
|
87
|
+
const dir = (0, files_1.getPluginDirPathLocalized)({
|
|
88
|
+
localizationDir,
|
|
89
|
+
pluginId,
|
|
90
|
+
});
|
|
91
|
+
const sourceFile = node_path_1.default.join(dir, 'current.json');
|
|
92
|
+
const dest = node_path_1.default.join(dir, `version-${version}.json`);
|
|
93
|
+
if (await (0, fs_1.pathExists)(sourceFile)) {
|
|
94
|
+
await fs_1.fs.cp(sourceFile, dest, { verbatimSymlinks: true });
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
logger_1.default.warn `${pluginIdLogPrefix}: i18n translation file does not exist in path=${sourceFile}. Skipping.`;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}));
|
|
101
|
+
await createVersionedSidebarFile({
|
|
102
|
+
siteDir,
|
|
103
|
+
pluginId,
|
|
104
|
+
version,
|
|
105
|
+
sidebarPath,
|
|
106
|
+
});
|
|
107
|
+
// Update versions.json file.
|
|
108
|
+
versions.unshift(version);
|
|
109
|
+
await (0, fs_1.outputFile)((0, files_1.getVersionsFilePath)(siteDir, pluginId), `${JSON.stringify(versions, null, 2)}\n`);
|
|
110
|
+
logger_1.default.success `name=${pluginIdLogPrefix}: version name=${version} created!`;
|
|
111
|
+
}
|
|
112
|
+
// TODO try to remove this workaround
|
|
113
|
+
// Why use a default export instead of named exports here?
|
|
114
|
+
// This is only to make Jest mocking happy
|
|
115
|
+
// After upgrading Jest/SWC we got this weird mocking error in extendCli tests
|
|
116
|
+
// "spyOn: Cannot redefine property cliDocsVersionCommand"
|
|
117
|
+
// I tried various workarounds, and it's the only one that worked :/
|
|
118
|
+
// See also:
|
|
119
|
+
// - https://pyk.sh/fixing-typeerror-cannot-redefine-property-x-error-in-jest-tests#heading-solution-2-using-barrel-imports
|
|
120
|
+
// - https://github.com/aelbore/esbuild-jest/issues/26
|
|
121
|
+
// - https://stackoverflow.com/questions/67872622/jest-spyon-not-working-on-index-file-cannot-redefine-property/69951703#69951703
|
|
122
|
+
exports.default = {
|
|
123
|
+
cliDocsVersionCommand,
|
|
124
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
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 ReactNode } from 'react';
|
|
8
|
+
import type { PropDocContent } from '@docusaurus/plugin-content-docs';
|
|
9
|
+
/**
|
|
10
|
+
* The React context value returned by the `useDoc()` hook.
|
|
11
|
+
* It contains useful data related to the currently browsed doc.
|
|
12
|
+
*/
|
|
13
|
+
export type DocContextValue = Pick<PropDocContent, 'metadata' | 'frontMatter' | 'toc' | 'assets' | 'contentTitle'>;
|
|
14
|
+
/**
|
|
15
|
+
* This is a very thin layer around the `content` received from the MDX loader.
|
|
16
|
+
* It provides metadata about the doc to the children tree.
|
|
17
|
+
*/
|
|
18
|
+
export declare function DocProvider({ children, content, }: {
|
|
19
|
+
children: ReactNode;
|
|
20
|
+
content: PropDocContent;
|
|
21
|
+
}): ReactNode;
|
|
22
|
+
/**
|
|
23
|
+
* Returns the data of the currently browsed doc. Gives access to the doc's MDX
|
|
24
|
+
* Component, front matter, metadata, TOC, etc. When swizzling a low-level
|
|
25
|
+
* component (e.g. the "Edit this page" link) and you need some extra metadata,
|
|
26
|
+
* you don't have to drill the props all the way through the component tree:
|
|
27
|
+
* simply use this hook instead.
|
|
28
|
+
*/
|
|
29
|
+
export declare function useDoc(): DocContextValue;
|
|
@@ -0,0 +1,47 @@
|
|
|
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 React, { useMemo, useContext } from 'react';
|
|
8
|
+
import { ReactContextError } from '@docusaurus/theme-common';
|
|
9
|
+
const Context = React.createContext(null);
|
|
10
|
+
/**
|
|
11
|
+
* Note: we don't use `PropDoc` as context value on purpose. Metadata is
|
|
12
|
+
* currently stored inside the MDX component, but we may want to change that in
|
|
13
|
+
* the future. This layer is a good opportunity to decouple storage from
|
|
14
|
+
* consuming API, potentially allowing us to provide metadata as both props and
|
|
15
|
+
* route context without duplicating the chunks in the future.
|
|
16
|
+
*/
|
|
17
|
+
function useContextValue(content) {
|
|
18
|
+
return useMemo(() => ({
|
|
19
|
+
metadata: content.metadata,
|
|
20
|
+
frontMatter: content.frontMatter,
|
|
21
|
+
assets: content.assets,
|
|
22
|
+
contentTitle: content.contentTitle,
|
|
23
|
+
toc: content.toc,
|
|
24
|
+
}), [content]);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* This is a very thin layer around the `content` received from the MDX loader.
|
|
28
|
+
* It provides metadata about the doc to the children tree.
|
|
29
|
+
*/
|
|
30
|
+
export function DocProvider({ children, content, }) {
|
|
31
|
+
const contextValue = useContextValue(content);
|
|
32
|
+
return <Context value={contextValue}>{children}</Context>;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Returns the data of the currently browsed doc. Gives access to the doc's MDX
|
|
36
|
+
* Component, front matter, metadata, TOC, etc. When swizzling a low-level
|
|
37
|
+
* component (e.g. the "Edit this page" link) and you need some extra metadata,
|
|
38
|
+
* you don't have to drill the props all the way through the component tree:
|
|
39
|
+
* simply use this hook instead.
|
|
40
|
+
*/
|
|
41
|
+
export function useDoc() {
|
|
42
|
+
const doc = useContext(Context);
|
|
43
|
+
if (doc === null) {
|
|
44
|
+
throw new ReactContextError('DocProvider');
|
|
45
|
+
}
|
|
46
|
+
return doc;
|
|
47
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
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 ReactNode } from 'react';
|
|
8
|
+
type ContextValue = {
|
|
9
|
+
/**
|
|
10
|
+
* The item that the user last opened, `null` when there's none open. On
|
|
11
|
+
* initial render, it will always be `null`, which doesn't necessarily mean
|
|
12
|
+
* there's no category open (can have 0, 1, or many being initially open).
|
|
13
|
+
*/
|
|
14
|
+
expandedItem: number | null;
|
|
15
|
+
/**
|
|
16
|
+
* Set the currently expanded item, when the user opens one. Set the value to
|
|
17
|
+
* `null` when the user closes an open category.
|
|
18
|
+
*/
|
|
19
|
+
setExpandedItem: (a: number | null) => void;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Should be used to wrap one sidebar category level. This provider syncs the
|
|
23
|
+
* expanded states of all sibling categories, and categories can choose to
|
|
24
|
+
* collapse itself if another one is expanded.
|
|
25
|
+
*/
|
|
26
|
+
export declare function DocSidebarItemsExpandedStateProvider({ children, }: {
|
|
27
|
+
children: ReactNode;
|
|
28
|
+
}): ReactNode;
|
|
29
|
+
export declare function useDocSidebarItemsExpandedState(): ContextValue;
|
|
30
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
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 React, { useMemo, useState, useContext } from 'react';
|
|
8
|
+
import { ReactContextError } from '@docusaurus/theme-common';
|
|
9
|
+
const EmptyContext = Symbol('EmptyContext');
|
|
10
|
+
const Context = React.createContext(EmptyContext);
|
|
11
|
+
/**
|
|
12
|
+
* Should be used to wrap one sidebar category level. This provider syncs the
|
|
13
|
+
* expanded states of all sibling categories, and categories can choose to
|
|
14
|
+
* collapse itself if another one is expanded.
|
|
15
|
+
*/
|
|
16
|
+
export function DocSidebarItemsExpandedStateProvider({ children, }) {
|
|
17
|
+
const [expandedItem, setExpandedItem] = useState(null);
|
|
18
|
+
const contextValue = useMemo(() => ({ expandedItem, setExpandedItem }), [expandedItem]);
|
|
19
|
+
return <Context value={contextValue}>{children}</Context>;
|
|
20
|
+
}
|
|
21
|
+
export function useDocSidebarItemsExpandedState() {
|
|
22
|
+
const value = useContext(Context);
|
|
23
|
+
if (value === EmptyContext) {
|
|
24
|
+
throw new ReactContextError('DocSidebarItemsExpandedStateProvider');
|
|
25
|
+
}
|
|
26
|
+
return value;
|
|
27
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
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 { GlobalPluginData, GlobalVersion, ActivePlugin, ActiveDocContext, DocVersionSuggestions } from '@docusaurus/plugin-content-docs/client';
|
|
8
|
+
import type { UseDataOptions } from '@docusaurus/types';
|
|
9
|
+
export declare function getActivePlugin(allPluginData: {
|
|
10
|
+
[pluginId: string]: GlobalPluginData;
|
|
11
|
+
}, pathname: string, options?: UseDataOptions): ActivePlugin | undefined;
|
|
12
|
+
export declare const getLatestVersion: (data: GlobalPluginData) => GlobalVersion;
|
|
13
|
+
export declare function getActiveVersion(data: GlobalPluginData, pathname: string): GlobalVersion | undefined;
|
|
14
|
+
export declare function getActiveDocContext(data: GlobalPluginData, pathname: string): ActiveDocContext;
|
|
15
|
+
export declare function getDocVersionSuggestions(data: GlobalPluginData, pathname: string): DocVersionSuggestions;
|
|
@@ -0,0 +1,86 @@
|
|
|
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 { matchPath } from '@docusaurus/router';
|
|
8
|
+
// This code is not part of the api surface, not in ./theme on purpose
|
|
9
|
+
// get the data of the plugin that is currently "active"
|
|
10
|
+
// ie the docs of that plugin are currently browsed
|
|
11
|
+
// it is useful to support multiple docs plugin instances
|
|
12
|
+
export function getActivePlugin(allPluginData, pathname, options = {}) {
|
|
13
|
+
const activeEntry = Object.entries(allPluginData)
|
|
14
|
+
// Route sorting: '/android/foo' should match '/android' instead of '/'
|
|
15
|
+
.sort((a, b) => b[1].path.localeCompare(a[1].path))
|
|
16
|
+
.find(([, pluginData]) => !!matchPath(pathname, {
|
|
17
|
+
path: pluginData.path,
|
|
18
|
+
exact: false,
|
|
19
|
+
strict: false,
|
|
20
|
+
}));
|
|
21
|
+
const activePlugin = activeEntry
|
|
22
|
+
? { pluginId: activeEntry[0], pluginData: activeEntry[1] }
|
|
23
|
+
: undefined;
|
|
24
|
+
if (!activePlugin && options.failfast) {
|
|
25
|
+
throw new Error(`Can't find active docs plugin for "${pathname}" pathname, while it was expected to be found. Maybe you tried to use a docs feature that can only be used on a docs-related page? Existing docs plugin paths are: ${Object.values(allPluginData)
|
|
26
|
+
.map((plugin) => plugin.path)
|
|
27
|
+
.join(', ')}`);
|
|
28
|
+
}
|
|
29
|
+
return activePlugin;
|
|
30
|
+
}
|
|
31
|
+
export const getLatestVersion = (data) => data.versions.find((version) => version.isLast);
|
|
32
|
+
export function getActiveVersion(data, pathname) {
|
|
33
|
+
// Sort paths so that a match-all version like /docs/* is matched last
|
|
34
|
+
// Otherwise /docs/* would match /docs/1.0.0/* routes
|
|
35
|
+
// This is simplified but similar to the core sortRoutes() logic
|
|
36
|
+
const sortedVersions = [...data.versions].sort((a, b) => {
|
|
37
|
+
if (a.path === b.path) {
|
|
38
|
+
return 0;
|
|
39
|
+
}
|
|
40
|
+
if (a.path.includes(b.path)) {
|
|
41
|
+
return -1;
|
|
42
|
+
}
|
|
43
|
+
if (b.path.includes(a.path)) {
|
|
44
|
+
return 1;
|
|
45
|
+
}
|
|
46
|
+
return 0;
|
|
47
|
+
});
|
|
48
|
+
return sortedVersions.find((version) => !!matchPath(pathname, {
|
|
49
|
+
path: version.path,
|
|
50
|
+
exact: false,
|
|
51
|
+
strict: false,
|
|
52
|
+
}));
|
|
53
|
+
}
|
|
54
|
+
export function getActiveDocContext(data, pathname) {
|
|
55
|
+
const activeVersion = getActiveVersion(data, pathname);
|
|
56
|
+
const activeDoc = activeVersion?.docs.find((doc) => !!matchPath(pathname, {
|
|
57
|
+
path: doc.path,
|
|
58
|
+
exact: true,
|
|
59
|
+
strict: false,
|
|
60
|
+
}));
|
|
61
|
+
function getAlternateVersionDocs(docId) {
|
|
62
|
+
const result = {};
|
|
63
|
+
data.versions.forEach((version) => {
|
|
64
|
+
version.docs.forEach((doc) => {
|
|
65
|
+
if (doc.id === docId) {
|
|
66
|
+
result[version.name] = doc;
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
72
|
+
const alternateVersionDocs = activeDoc
|
|
73
|
+
? getAlternateVersionDocs(activeDoc.id)
|
|
74
|
+
: {};
|
|
75
|
+
return {
|
|
76
|
+
activeVersion,
|
|
77
|
+
activeDoc,
|
|
78
|
+
alternateDocVersions: alternateVersionDocs,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
export function getDocVersionSuggestions(data, pathname) {
|
|
82
|
+
const latestVersion = getLatestVersion(data);
|
|
83
|
+
const activeDocContext = getActiveDocContext(data, pathname);
|
|
84
|
+
const latestDocSuggestion = activeDocContext.alternateDocVersions[latestVersion.name];
|
|
85
|
+
return { latestDocSuggestion, latestVersionSuggestion: latestVersion };
|
|
86
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
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 ReactNode } from 'react';
|
|
8
|
+
import { type GlobalVersion } from '@docusaurus/plugin-content-docs/client';
|
|
9
|
+
/**
|
|
10
|
+
* This is a maybe-layer. If the docs plugin is not enabled, this provider is a
|
|
11
|
+
* simple pass-through.
|
|
12
|
+
*/
|
|
13
|
+
export declare function DocsPreferredVersionContextProvider({ children, }: {
|
|
14
|
+
children: ReactNode;
|
|
15
|
+
}): ReactNode;
|
|
16
|
+
/**
|
|
17
|
+
* Returns a read-write interface to a plugin's preferred version. The
|
|
18
|
+
* "preferred version" is defined as the last version that the user visited.
|
|
19
|
+
* For example, if a user is using v3, even when v4 is later published, the user
|
|
20
|
+
* would still be browsing v3 docs when she opens the website next time. Note,
|
|
21
|
+
* the `preferredVersion` attribute will always be `null` before mount.
|
|
22
|
+
*/
|
|
23
|
+
export declare function useDocsPreferredVersion(pluginId?: string | undefined): {
|
|
24
|
+
preferredVersion: GlobalVersion | null;
|
|
25
|
+
savePreferredVersionName: (versionName: string) => void;
|
|
26
|
+
};
|
|
27
|
+
export declare function useDocsPreferredVersionByPluginId(): {
|
|
28
|
+
[pluginId: string]: GlobalVersion | null;
|
|
29
|
+
};
|
|
@@ -0,0 +1,124 @@
|
|
|
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 React, { useContext, useEffect, useMemo, useState, useCallback, } from 'react';
|
|
8
|
+
import { useAllDocsData, useDocsData, } from '@docusaurus/plugin-content-docs/client';
|
|
9
|
+
import { DEFAULT_PLUGIN_ID } from '@docusaurus/constants';
|
|
10
|
+
import { useThemeConfig } from '@docusaurus/theme-common';
|
|
11
|
+
import { ReactContextError, createStorageSlot } from '@docusaurus/theme-common';
|
|
12
|
+
const storageKey = (pluginId) => `docs-preferred-version-${pluginId}`;
|
|
13
|
+
const DocsPreferredVersionStorage = {
|
|
14
|
+
save: (pluginId, persistence, versionName) => {
|
|
15
|
+
createStorageSlot(storageKey(pluginId), { persistence }).set(versionName);
|
|
16
|
+
},
|
|
17
|
+
read: (pluginId, persistence) => createStorageSlot(storageKey(pluginId), { persistence }).get(),
|
|
18
|
+
clear: (pluginId, persistence) => {
|
|
19
|
+
createStorageSlot(storageKey(pluginId), { persistence }).del();
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Initial state is always null as we can't read local storage from node SSR
|
|
24
|
+
*/
|
|
25
|
+
const getInitialState = (pluginIds) => Object.fromEntries(pluginIds.map((id) => [id, { preferredVersionName: null }]));
|
|
26
|
+
/**
|
|
27
|
+
* Read storage for all docs plugins, assigning each doc plugin a preferred
|
|
28
|
+
* version (if found)
|
|
29
|
+
*/
|
|
30
|
+
function readStorageState({ pluginIds, versionPersistence, allDocsData, }) {
|
|
31
|
+
/**
|
|
32
|
+
* The storage value we read might be stale, and belong to a version that does
|
|
33
|
+
* not exist in the site anymore. In such case, we remove the storage value to
|
|
34
|
+
* avoid downstream errors.
|
|
35
|
+
*/
|
|
36
|
+
function restorePluginState(pluginId) {
|
|
37
|
+
const preferredVersionNameUnsafe = DocsPreferredVersionStorage.read(pluginId, versionPersistence);
|
|
38
|
+
const pluginData = allDocsData[pluginId];
|
|
39
|
+
const versionExists = pluginData.versions.some((version) => version.name === preferredVersionNameUnsafe);
|
|
40
|
+
if (versionExists) {
|
|
41
|
+
return { preferredVersionName: preferredVersionNameUnsafe };
|
|
42
|
+
}
|
|
43
|
+
DocsPreferredVersionStorage.clear(pluginId, versionPersistence);
|
|
44
|
+
return { preferredVersionName: null };
|
|
45
|
+
}
|
|
46
|
+
return Object.fromEntries(pluginIds.map((id) => [id, restorePluginState(id)]));
|
|
47
|
+
}
|
|
48
|
+
function useVersionPersistence() {
|
|
49
|
+
return useThemeConfig().docs.versionPersistence;
|
|
50
|
+
}
|
|
51
|
+
const Context = React.createContext(null);
|
|
52
|
+
function useContextValue() {
|
|
53
|
+
const allDocsData = useAllDocsData();
|
|
54
|
+
const versionPersistence = useVersionPersistence();
|
|
55
|
+
const pluginIds = useMemo(() => Object.keys(allDocsData), [allDocsData]);
|
|
56
|
+
// Initial state is empty, as we can't read browser storage in node/SSR
|
|
57
|
+
const [state, setState] = useState(() => getInitialState(pluginIds));
|
|
58
|
+
// On mount, we set the state read from browser storage
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
setState(readStorageState({ allDocsData, versionPersistence, pluginIds }));
|
|
61
|
+
}, [allDocsData, versionPersistence, pluginIds]);
|
|
62
|
+
// The API that we expose to consumer hooks (memo for constant object)
|
|
63
|
+
const api = useMemo(() => {
|
|
64
|
+
function savePreferredVersion(pluginId, versionName) {
|
|
65
|
+
DocsPreferredVersionStorage.save(pluginId, versionPersistence, versionName);
|
|
66
|
+
setState((s) => ({
|
|
67
|
+
...s,
|
|
68
|
+
[pluginId]: { preferredVersionName: versionName },
|
|
69
|
+
}));
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
savePreferredVersion,
|
|
73
|
+
};
|
|
74
|
+
}, [versionPersistence]);
|
|
75
|
+
return [state, api];
|
|
76
|
+
}
|
|
77
|
+
function DocsPreferredVersionContextProviderUnsafe({ children, }) {
|
|
78
|
+
const value = useContextValue();
|
|
79
|
+
return <Context value={value}>{children}</Context>;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* This is a maybe-layer. If the docs plugin is not enabled, this provider is a
|
|
83
|
+
* simple pass-through.
|
|
84
|
+
*/
|
|
85
|
+
export function DocsPreferredVersionContextProvider({ children, }) {
|
|
86
|
+
return (<DocsPreferredVersionContextProviderUnsafe>
|
|
87
|
+
{children}
|
|
88
|
+
</DocsPreferredVersionContextProviderUnsafe>);
|
|
89
|
+
}
|
|
90
|
+
function useDocsPreferredVersionContext() {
|
|
91
|
+
const value = useContext(Context);
|
|
92
|
+
if (!value) {
|
|
93
|
+
throw new ReactContextError('DocsPreferredVersionContextProvider');
|
|
94
|
+
}
|
|
95
|
+
return value;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Returns a read-write interface to a plugin's preferred version. The
|
|
99
|
+
* "preferred version" is defined as the last version that the user visited.
|
|
100
|
+
* For example, if a user is using v3, even when v4 is later published, the user
|
|
101
|
+
* would still be browsing v3 docs when she opens the website next time. Note,
|
|
102
|
+
* the `preferredVersion` attribute will always be `null` before mount.
|
|
103
|
+
*/
|
|
104
|
+
export function useDocsPreferredVersion(pluginId = DEFAULT_PLUGIN_ID) {
|
|
105
|
+
const docsData = useDocsData(pluginId);
|
|
106
|
+
const [state, api] = useDocsPreferredVersionContext();
|
|
107
|
+
const { preferredVersionName } = state[pluginId];
|
|
108
|
+
const preferredVersion = docsData.versions.find((version) => version.name === preferredVersionName) ?? null;
|
|
109
|
+
const savePreferredVersionName = useCallback((versionName) => {
|
|
110
|
+
api.savePreferredVersion(pluginId, versionName);
|
|
111
|
+
}, [api, pluginId]);
|
|
112
|
+
return { preferredVersion, savePreferredVersionName };
|
|
113
|
+
}
|
|
114
|
+
export function useDocsPreferredVersionByPluginId() {
|
|
115
|
+
const allDocsData = useAllDocsData();
|
|
116
|
+
const [state] = useDocsPreferredVersionContext();
|
|
117
|
+
function getPluginIdPreferredVersion(pluginId) {
|
|
118
|
+
const docsData = allDocsData[pluginId];
|
|
119
|
+
const { preferredVersionName } = state[pluginId];
|
|
120
|
+
return (docsData.versions.find((version) => version.name === preferredVersionName) ?? null);
|
|
121
|
+
}
|
|
122
|
+
const pluginIds = Object.keys(allDocsData);
|
|
123
|
+
return Object.fromEntries(pluginIds.map((id) => [id, getPluginIdPreferredVersion(id)]));
|
|
124
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
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
|
+
/** The search tag to append as each doc's metadata. */
|
|
8
|
+
export declare function getDocsVersionSearchTag(pluginId: string, versionName: string): string;
|
|
9
|
+
/**
|
|
10
|
+
* Gets the relevant docs tags to search.
|
|
11
|
+
* This is the logic that powers the contextual search feature.
|
|
12
|
+
*
|
|
13
|
+
* If user is browsing Android 1.4 docs, he'll get presented with:
|
|
14
|
+
* - Android '1.4' docs
|
|
15
|
+
* - iOS 'preferred | latest' docs
|
|
16
|
+
*
|
|
17
|
+
* The result is generic and not coupled to Algolia/DocSearch on purpose.
|
|
18
|
+
*/
|
|
19
|
+
export declare function useDocsContextualSearchTags(): string[];
|
|
@@ -0,0 +1,39 @@
|
|
|
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 { useAllDocsData, useActivePluginAndVersion, } from '@docusaurus/plugin-content-docs/client';
|
|
8
|
+
import { useDocsPreferredVersionByPluginId } from './docsPreferredVersion';
|
|
9
|
+
/** The search tag to append as each doc's metadata. */
|
|
10
|
+
export function getDocsVersionSearchTag(pluginId, versionName) {
|
|
11
|
+
return `docs-${pluginId}-${versionName}`;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Gets the relevant docs tags to search.
|
|
15
|
+
* This is the logic that powers the contextual search feature.
|
|
16
|
+
*
|
|
17
|
+
* If user is browsing Android 1.4 docs, he'll get presented with:
|
|
18
|
+
* - Android '1.4' docs
|
|
19
|
+
* - iOS 'preferred | latest' docs
|
|
20
|
+
*
|
|
21
|
+
* The result is generic and not coupled to Algolia/DocSearch on purpose.
|
|
22
|
+
*/
|
|
23
|
+
export function useDocsContextualSearchTags() {
|
|
24
|
+
const allDocsData = useAllDocsData();
|
|
25
|
+
const activePluginAndVersion = useActivePluginAndVersion();
|
|
26
|
+
const docsPreferredVersionByPluginId = useDocsPreferredVersionByPluginId();
|
|
27
|
+
// This can't use more specialized hooks because we are mapping over all
|
|
28
|
+
// plugin instances.
|
|
29
|
+
function getDocPluginTags(pluginId) {
|
|
30
|
+
const activeVersion = activePluginAndVersion?.activePlugin.pluginId === pluginId
|
|
31
|
+
? activePluginAndVersion.activeVersion
|
|
32
|
+
: undefined;
|
|
33
|
+
const preferredVersion = docsPreferredVersionByPluginId[pluginId];
|
|
34
|
+
const latestVersion = allDocsData[pluginId].versions.find((v) => v.isLast);
|
|
35
|
+
const version = activeVersion ?? preferredVersion ?? latestVersion;
|
|
36
|
+
return getDocsVersionSearchTag(pluginId, version.name);
|
|
37
|
+
}
|
|
38
|
+
return [...Object.keys(allDocsData).map(getDocPluginTags)];
|
|
39
|
+
}
|