refactor(content-docs): deduplicate types, JSDoc for some APIs (#7027)

* refactor(content-docs): deduplicate types, JSDoc for some APIs

* little refactor
This commit is contained in:
Joshua Chen 2022-03-27 12:57:15 +08:00 committed by GitHub
parent b842197ac6
commit 2bcac29cd4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
38 changed files with 715 additions and 521 deletions

View file

@ -21,21 +21,21 @@ import toc from './remark/toc';
import unwrapMdxCodeBlocks from './remark/unwrapMdxCodeBlocks'; import unwrapMdxCodeBlocks from './remark/unwrapMdxCodeBlocks';
import transformImage from './remark/transformImage'; import transformImage from './remark/transformImage';
import transformLinks from './remark/transformLinks'; import transformLinks from './remark/transformLinks';
import type {RemarkAndRehypePluginOptions} from '@docusaurus/mdx-loader'; import type {MDXOptions} from '@docusaurus/mdx-loader';
import type {LoaderContext} from 'webpack'; import type {LoaderContext} from 'webpack';
const { const {
loaders: {inlineMarkdownImageFileLoader}, loaders: {inlineMarkdownImageFileLoader},
} = getFileLoaderUtils(); } = getFileLoaderUtils();
const DEFAULT_OPTIONS: RemarkAndRehypePluginOptions = { const DEFAULT_OPTIONS: MDXOptions = {
rehypePlugins: [], rehypePlugins: [],
remarkPlugins: [unwrapMdxCodeBlocks, emoji, headings, toc], remarkPlugins: [unwrapMdxCodeBlocks, emoji, headings, toc],
beforeDefaultRemarkPlugins: [], beforeDefaultRemarkPlugins: [],
beforeDefaultRehypePlugins: [], beforeDefaultRehypePlugins: [],
}; };
type Options = RemarkAndRehypePluginOptions & { type Options = MDXOptions & {
staticDirs: string[]; staticDirs: string[];
siteDir: string; siteDir: string;
isMDXPartial?: (filePath: string) => boolean; isMDXPartial?: (filePath: string) => boolean;

View file

@ -7,12 +7,12 @@
import type {Plugin} from 'unified'; import type {Plugin} from 'unified';
export type RemarkOrRehypePlugin = export type MDXPlugin =
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
[Plugin<any[]>, any] | Plugin<any[]>; [Plugin<any[]>, any] | Plugin<any[]>;
export type RemarkAndRehypePluginOptions = { export type MDXOptions = {
remarkPlugins: RemarkOrRehypePlugin[]; remarkPlugins: MDXPlugin[];
rehypePlugins: RemarkOrRehypePlugin[]; rehypePlugins: MDXPlugin[];
beforeDefaultRemarkPlugins: RemarkOrRehypePlugin[]; beforeDefaultRemarkPlugins: MDXPlugin[];
beforeDefaultRehypePlugins: RemarkOrRehypePlugin[]; beforeDefaultRehypePlugins: MDXPlugin[];
}; };

View file

@ -6,8 +6,8 @@
*/ */
declare module '@docusaurus/plugin-content-blog' { declare module '@docusaurus/plugin-content-blog' {
import type {RemarkAndRehypePluginOptions} from '@docusaurus/mdx-loader'; import type {MDXOptions} from '@docusaurus/mdx-loader';
import type {FrontMatterTag} from '@docusaurus/utils'; import type {FrontMatterTag, Tag} from '@docusaurus/utils';
import type {Overwrite} from 'utility-types'; import type {Overwrite} from 'utility-types';
export interface Assets { export interface Assets {
@ -81,10 +81,7 @@ declare module '@docusaurus/plugin-content-blog' {
* @see {@link BlogPostMetadata.tags} * @see {@link BlogPostMetadata.tags}
*/ */
tags?: FrontMatterTag[]; tags?: FrontMatterTag[];
/** /** Custom slug appended after `/<baseUrl>/<routeBasePath>/` */
* Custom slug appended after /<baseUrl>/<routeBasePath>/
* @see {@link BlogPostMetadata.slug}
*/
slug?: string; slug?: string;
/** /**
* Marks the post as draft and excludes it from the production build. * Marks the post as draft and excludes it from the production build.
@ -130,25 +127,18 @@ declare module '@docusaurus/plugin-content-blog' {
/** @deprecated v1 legacy */ /** @deprecated v1 legacy */
authorImageURL?: string; authorImageURL?: string;
/** /** Used in the head meta. Should use `assets.image` in priority. */
* @see {@link BlogPostMetadata.image}
*/
image?: string; image?: string;
/** /** Used in the head meta. */
* Used in the head meta
*/
keywords?: string[]; keywords?: string[];
/** /** Hide the right TOC. */
* Hide the right TOC
*/
hide_table_of_contents?: boolean; hide_table_of_contents?: boolean;
/** /**
* Minimum TOC heading level * Minimum TOC heading level. Must be between 2 and 6 and lower or equal to
* the max value.
*/ */
toc_min_heading_level?: number; toc_min_heading_level?: number;
/** /** Maximum TOC heading level. Must be between 2 and 6. */
* Maximum TOC heading level
*/
toc_max_heading_level?: number; toc_max_heading_level?: number;
}; };
@ -175,9 +165,7 @@ declare module '@docusaurus/plugin-content-blog' {
| (string | BlogPostFrontMatterAuthor)[]; | (string | BlogPostFrontMatterAuthor)[];
export type BlogPostMetadata = { export type BlogPostMetadata = {
/** /** Path to the Markdown source, with `@site` alias. */
* Path to the Markdown source, with `@site` alias.
*/
readonly source: string; readonly source: string;
/** /**
* Used to generate the page h1 heading, tab title, and pagination title. * Used to generate the page h1 heading, tab title, and pagination title.
@ -193,9 +181,7 @@ declare module '@docusaurus/plugin-content-blog' {
* render the date regardless of the existence of `Intl.DateTimeFormat`. * render the date regardless of the existence of `Intl.DateTimeFormat`.
*/ */
readonly formattedDate: string; readonly formattedDate: string;
/** /** Full link including base URL. */
* Full link including base URL.
*/
readonly permalink: string; readonly permalink: string;
/** /**
* Description used in the meta. Could be an empty string (empty content) * Description used in the meta. Could be an empty string (empty content)
@ -229,17 +215,10 @@ declare module '@docusaurus/plugin-content-blog' {
* `assets.authorsImageUrls` on client side. * `assets.authorsImageUrls` on client side.
*/ */
readonly authors: Author[]; readonly authors: Author[];
/** /** Front matter, as-is. */
* Front matter, as-is.
*/
readonly frontMatter: BlogPostFrontMatter & {[key: string]: unknown}; readonly frontMatter: BlogPostFrontMatter & {[key: string]: unknown};
/** /** Tags, normalized. */
* Tags, normalized. readonly tags: Tag[];
*/
readonly tags: readonly {
readonly label: string;
readonly permalink: string;
}[];
}; };
/** /**
* @returns The edit URL that's directly plugged into metadata. * @returns The edit URL that's directly plugged into metadata.
@ -250,17 +229,11 @@ declare module '@docusaurus/plugin-content-blog' {
* site path. Usually the same as `options.path` but can be localized * site path. Usually the same as `options.path` but can be localized
*/ */
blogDirPath: string; blogDirPath: string;
/** /** Path to this post file, relative to `blogDirPath`. */
* Path to this post file, relative to `blogDirPath`
*/
blogPath: string; blogPath: string;
/** /** @see {@link BlogPostMetadata.permalink} */
* @see {@link BlogPostMetadata.permalink}
*/
permalink: string; permalink: string;
/** /** Locale name. */
* Locale name.
*/
locale: string; locale: string;
}) => string | undefined; }) => string | undefined;
@ -325,7 +298,7 @@ declare module '@docusaurus/plugin-content-blog' {
/** /**
* Plugin options after normalization. * Plugin options after normalization.
*/ */
export type PluginOptions = RemarkAndRehypePluginOptions & { export type PluginOptions = MDXOptions & {
/** Plugin ID. */ /** Plugin ID. */
id?: string; id?: string;
/** /**

View file

@ -169,7 +169,9 @@ exports[`translateLoadedContent returns translated loaded content 1`] = `
}, },
], ],
"isLast": true, "isLast": true,
"label": "current label (translated)",
"mainDocId": "", "mainDocId": "",
"path": "/docs/",
"routePriority": undefined, "routePriority": undefined,
"sidebarFilePath": "any", "sidebarFilePath": "any",
"sidebars": { "sidebars": {
@ -221,9 +223,7 @@ exports[`translateLoadedContent returns translated loaded content 1`] = `
}, },
], ],
}, },
"versionLabel": "current label (translated)",
"versionName": "current", "versionName": "current",
"versionPath": "/docs/",
}, },
{ {
"contentPath": "any", "contentPath": "any",
@ -311,7 +311,9 @@ exports[`translateLoadedContent returns translated loaded content 1`] = `
}, },
], ],
"isLast": true, "isLast": true,
"label": "2.0.0 label (translated)",
"mainDocId": "", "mainDocId": "",
"path": "/docs/",
"routePriority": undefined, "routePriority": undefined,
"sidebarFilePath": "any", "sidebarFilePath": "any",
"sidebars": { "sidebars": {
@ -363,9 +365,7 @@ exports[`translateLoadedContent returns translated loaded content 1`] = `
}, },
], ],
}, },
"versionLabel": "2.0.0 label (translated)",
"versionName": "2.0.0", "versionName": "2.0.0",
"versionPath": "/docs/",
}, },
{ {
"contentPath": "any", "contentPath": "any",
@ -453,7 +453,9 @@ exports[`translateLoadedContent returns translated loaded content 1`] = `
}, },
], ],
"isLast": true, "isLast": true,
"label": "1.0.0 label (translated)",
"mainDocId": "", "mainDocId": "",
"path": "/docs/",
"routePriority": undefined, "routePriority": undefined,
"sidebarFilePath": "any", "sidebarFilePath": "any",
"sidebars": { "sidebars": {
@ -505,9 +507,7 @@ exports[`translateLoadedContent returns translated loaded content 1`] = `
}, },
], ],
}, },
"versionLabel": "1.0.0 label (translated)",
"versionName": "1.0.0", "versionName": "1.0.0",
"versionPath": "/docs/",
}, },
], ],
} }

View file

@ -18,16 +18,14 @@ import {
import {loadSidebars} from '../sidebars'; import {loadSidebars} from '../sidebars';
import type {Sidebars} from '../sidebars/types'; import type {Sidebars} from '../sidebars/types';
import {readVersionsMetadata} from '../versions'; import {readVersionsMetadata} from '../versions';
import type { import type {DocFile} from '../types';
DocFile,
DocMetadataBase,
VersionMetadata,
DocNavLink,
} from '../types';
import type { import type {
MetadataOptions, MetadataOptions,
PluginOptions, PluginOptions,
EditUrlFunction, EditUrlFunction,
DocMetadataBase,
VersionMetadata,
PropNavigationLink,
} from '@docusaurus/plugin-content-docs'; } from '@docusaurus/plugin-content-docs';
import type {LoadContext} from '@docusaurus/types'; import type {LoadContext} from '@docusaurus/types';
import {DEFAULT_OPTIONS} from '../options'; import {DEFAULT_OPTIONS} from '../options';
@ -123,7 +121,11 @@ function createTestUtils({
} }
async function generateNavigation(docFiles: DocFile[]): Promise<{ async function generateNavigation(docFiles: DocFile[]): Promise<{
pagination: {prev?: DocNavLink; next?: DocNavLink; id: string}[]; pagination: {
prev?: PropNavigationLink;
next?: PropNavigationLink;
id: string;
}[];
sidebars: Sidebars; sidebars: Sidebars;
}> { }> {
const rawDocs = docFiles.map((docFile) => const rawDocs = docFiles.map((docFile) =>

View file

@ -6,7 +6,7 @@
*/ */
import {validateDocFrontMatter} from '../frontMatter'; import {validateDocFrontMatter} from '../frontMatter';
import type {DocFrontMatter} from '../types'; import type {DocFrontMatter} from '@docusaurus/plugin-content-docs';
import escapeStringRegexp from 'escape-string-regexp'; import escapeStringRegexp from 'escape-string-regexp';
function testField(params: { function testField(params: {

View file

@ -12,9 +12,9 @@ describe('toGlobalDataVersion', () => {
expect( expect(
toGlobalDataVersion({ toGlobalDataVersion({
versionName: 'current', versionName: 'current',
versionLabel: 'Label', label: 'Label',
isLast: true, isLast: true,
versionPath: '/current', path: '/current',
mainDocId: 'main', mainDocId: 'main',
docs: [ docs: [
{ {
@ -86,9 +86,9 @@ describe('toGlobalDataVersion', () => {
sidebar: 'tutorial', sidebar: 'tutorial',
}, },
], ],
versionBanner: 'unreleased', banner: 'unreleased',
versionBadge: true, badge: true,
versionClassName: 'current-cls', className: 'current-cls',
tagsPath: '/current/tags', tagsPath: '/current/tags',
contentPath: '', contentPath: '',
contentPathLocalized: '', contentPathLocalized: '',

View file

@ -16,7 +16,7 @@ describe('toTagDocListProp', () => {
it('works', () => { it('works', () => {
const tag: Tag = { const tag: Tag = {
name: 'tag1', label: 'tag1',
permalink: '/tag1', permalink: '/tag1',
docIds: ['id1', 'id3'], docIds: ['id1', 'id3'],
}; };
@ -54,7 +54,7 @@ describe('toTagDocListProp', () => {
expect(result).toEqual({ expect(result).toEqual({
allTagsPath, allTagsPath,
name: tag.name, name: tag.label,
permalink: tag.permalink, permalink: tag.permalink,
docs: [doc3, doc1], // docs sorted by title, ignore "id5" absence docs: [doc3, doc1], // docs sorted by title, ignore "id5" absence
}); });

View file

@ -5,12 +5,13 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import type {LoadedContent, DocMetadata, LoadedVersion} from '../types'; import type {LoadedContent, LoadedVersion} from '../types';
import {CURRENT_VERSION_NAME} from '../constants'; import {CURRENT_VERSION_NAME} from '../constants';
import { import {
getLoadedContentTranslationFiles, getLoadedContentTranslationFiles,
translateLoadedContent, translateLoadedContent,
} from '../translations'; } from '../translations';
import type {DocMetadata} from '@docusaurus/plugin-content-docs';
import {updateTranslationFileMessages} from '@docusaurus/utils'; import {updateTranslationFileMessages} from '@docusaurus/utils';
function createSampleDoc(doc: Pick<DocMetadata, 'id'>): DocMetadata { function createSampleDoc(doc: Pick<DocMetadata, 'id'>): DocMetadata {
@ -36,8 +37,8 @@ function createSampleVersion(
version: Pick<LoadedVersion, 'versionName'>, version: Pick<LoadedVersion, 'versionName'>,
): LoadedVersion { ): LoadedVersion {
return { return {
versionLabel: `${version.versionName} label`, label: `${version.versionName} label`,
versionPath: '/docs/', path: '/docs/',
mainDocId: '', mainDocId: '',
routePriority: undefined, routePriority: undefined,
sidebarFilePath: 'any', sidebarFilePath: 'any',
@ -45,21 +46,11 @@ function createSampleVersion(
contentPath: 'any', contentPath: 'any',
contentPathLocalized: 'any', contentPathLocalized: 'any',
docs: [ docs: [
createSampleDoc({ createSampleDoc({id: 'doc1'}),
id: 'doc1', createSampleDoc({id: 'doc2'}),
}), createSampleDoc({id: 'doc3'}),
createSampleDoc({ createSampleDoc({id: 'doc4'}),
id: 'doc2', createSampleDoc({id: 'doc5'}),
}),
createSampleDoc({
id: 'doc3',
}),
createSampleDoc({
id: 'doc4',
}),
createSampleDoc({
id: 'doc5',
}),
], ],
sidebars: { sidebars: {
docs: [ docs: [

View file

@ -15,9 +15,11 @@ import {
} from '../versions'; } from '../versions';
import {DEFAULT_OPTIONS} from '../options'; import {DEFAULT_OPTIONS} from '../options';
import {DEFAULT_PLUGIN_ID} from '@docusaurus/utils'; import {DEFAULT_PLUGIN_ID} from '@docusaurus/utils';
import type {VersionMetadata} from '../types';
import type {I18n} from '@docusaurus/types'; import type {I18n} from '@docusaurus/types';
import type {PluginOptions} from '@docusaurus/plugin-content-docs'; import type {
PluginOptions,
VersionMetadata,
} from '@docusaurus/plugin-content-docs';
const DefaultI18N: I18n = { const DefaultI18N: I18n = {
currentLocale: 'en', currentLocale: 'en',
@ -85,12 +87,12 @@ describe('readVersionsMetadata', () => {
routePriority: -1, routePriority: -1,
sidebarFilePath: undefined, sidebarFilePath: undefined,
tagsPath: '/docs/tags', tagsPath: '/docs/tags',
versionLabel: 'Next', label: 'Next',
versionName: 'current', versionName: 'current',
versionPath: '/docs', path: '/docs',
versionBanner: null, banner: null,
versionBadge: false, badge: false,
versionClassName: 'docs-version-current', className: 'docs-version-current',
}; };
return {simpleSiteDir, defaultOptions, defaultContext, vCurrent}; return {simpleSiteDir, defaultOptions, defaultContext, vCurrent};
} }
@ -120,7 +122,7 @@ describe('readVersionsMetadata', () => {
expect(versionsMetadata).toEqual([ expect(versionsMetadata).toEqual([
{ {
...vCurrent, ...vCurrent,
versionPath: '/myBaseUrl/docs', path: '/myBaseUrl/docs',
tagsPath: '/myBaseUrl/docs/tags', tagsPath: '/myBaseUrl/docs/tags',
}, },
]); ]);
@ -148,13 +150,13 @@ describe('readVersionsMetadata', () => {
expect(versionsMetadata).toEqual([ expect(versionsMetadata).toEqual([
{ {
...vCurrent, ...vCurrent,
versionPath: '/myBaseUrl/docs/current-path', path: '/myBaseUrl/docs/current-path',
versionLabel: 'current-label', label: 'current-label',
routePriority: undefined, routePriority: undefined,
sidebarFilePath: undefined, sidebarFilePath: undefined,
tagsPath: '/myBaseUrl/docs/current-path/tags', tagsPath: '/myBaseUrl/docs/current-path/tags',
versionEditUrl: undefined, editUrl: undefined,
versionEditUrlLocalized: undefined, editUrlLocalized: undefined,
}, },
]); ]);
}); });
@ -245,12 +247,12 @@ describe('readVersionsMetadata', () => {
routePriority: undefined, routePriority: undefined,
sidebarFilePath: path.join(versionedSiteDir, 'sidebars.json'), sidebarFilePath: path.join(versionedSiteDir, 'sidebars.json'),
tagsPath: '/docs/next/tags', tagsPath: '/docs/next/tags',
versionLabel: 'Next', label: 'Next',
versionName: 'current', versionName: 'current',
versionPath: '/docs/next', path: '/docs/next',
versionBanner: 'unreleased', banner: 'unreleased',
versionBadge: true, badge: true,
versionClassName: 'docs-version-current', className: 'docs-version-current',
}; };
const v101: VersionMetadata = { const v101: VersionMetadata = {
@ -269,12 +271,12 @@ describe('readVersionsMetadata', () => {
'versioned_sidebars/version-1.0.1-sidebars.json', 'versioned_sidebars/version-1.0.1-sidebars.json',
), ),
tagsPath: '/docs/tags', tagsPath: '/docs/tags',
versionLabel: '1.0.1', label: '1.0.1',
versionName: '1.0.1', versionName: '1.0.1',
versionPath: '/docs', path: '/docs',
versionBanner: null, banner: null,
versionBadge: true, badge: true,
versionClassName: 'docs-version-1.0.1', className: 'docs-version-1.0.1',
}; };
const v100: VersionMetadata = { const v100: VersionMetadata = {
@ -293,12 +295,12 @@ describe('readVersionsMetadata', () => {
'versioned_sidebars/version-1.0.0-sidebars.json', 'versioned_sidebars/version-1.0.0-sidebars.json',
), ),
tagsPath: '/docs/1.0.0/tags', tagsPath: '/docs/1.0.0/tags',
versionLabel: '1.0.0', label: '1.0.0',
versionName: '1.0.0', versionName: '1.0.0',
versionPath: '/docs/1.0.0', path: '/docs/1.0.0',
versionBanner: 'unmaintained', banner: 'unmaintained',
versionBadge: true, badge: true,
versionClassName: 'docs-version-1.0.0', className: 'docs-version-1.0.0',
}; };
const vWithSlugs: VersionMetadata = { const vWithSlugs: VersionMetadata = {
@ -317,12 +319,12 @@ describe('readVersionsMetadata', () => {
'versioned_sidebars/version-withSlugs-sidebars.json', 'versioned_sidebars/version-withSlugs-sidebars.json',
), ),
tagsPath: '/docs/withSlugs/tags', tagsPath: '/docs/withSlugs/tags',
versionLabel: 'withSlugs', label: 'withSlugs',
versionName: 'withSlugs', versionName: 'withSlugs',
versionPath: '/docs/withSlugs', path: '/docs/withSlugs',
versionBanner: 'unmaintained', banner: 'unmaintained',
versionBadge: true, badge: true,
versionClassName: 'docs-version-withSlugs', className: 'docs-version-withSlugs',
}; };
return { return {
@ -393,27 +395,27 @@ describe('readVersionsMetadata', () => {
{ {
...vCurrent, ...vCurrent,
tagsPath: '/docs/current-path/tags', tagsPath: '/docs/current-path/tags',
versionPath: '/docs/current-path', path: '/docs/current-path',
versionBanner: 'unmaintained', banner: 'unmaintained',
versionBadge: false, badge: false,
versionClassName: 'custom-current-className', className: 'custom-current-className',
}, },
{ {
...v101, ...v101,
isLast: false, isLast: false,
routePriority: undefined, routePriority: undefined,
tagsPath: '/docs/1.0.1/tags', tagsPath: '/docs/1.0.1/tags',
versionPath: '/docs/1.0.1', path: '/docs/1.0.1',
versionBanner: 'unreleased', banner: 'unreleased',
}, },
{ {
...v100, ...v100,
isLast: true, isLast: true,
routePriority: -1, routePriority: -1,
tagsPath: '/docs/tags', tagsPath: '/docs/tags',
versionLabel: '1.0.0-label', label: '1.0.0-label',
versionPath: '/docs', path: '/docs',
versionBanner: 'unreleased', banner: 'unreleased',
}, },
vWithSlugs, vWithSlugs,
]); ]);
@ -434,30 +436,30 @@ describe('readVersionsMetadata', () => {
expect(versionsMetadata).toEqual([ expect(versionsMetadata).toEqual([
{ {
...vCurrent, ...vCurrent,
versionEditUrl: editUrl:
'https://github.com/facebook/docusaurus/edit/main/website/docs', 'https://github.com/facebook/docusaurus/edit/main/website/docs',
versionEditUrlLocalized: editUrlLocalized:
'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/current', 'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/current',
}, },
{ {
...v101, ...v101,
versionEditUrl: editUrl:
'https://github.com/facebook/docusaurus/edit/main/website/versioned_docs/version-1.0.1', 'https://github.com/facebook/docusaurus/edit/main/website/versioned_docs/version-1.0.1',
versionEditUrlLocalized: editUrlLocalized:
'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/version-1.0.1', 'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/version-1.0.1',
}, },
{ {
...v100, ...v100,
versionEditUrl: editUrl:
'https://github.com/facebook/docusaurus/edit/main/website/versioned_docs/version-1.0.0', 'https://github.com/facebook/docusaurus/edit/main/website/versioned_docs/version-1.0.0',
versionEditUrlLocalized: editUrlLocalized:
'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/version-1.0.0', 'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/version-1.0.0',
}, },
{ {
...vWithSlugs, ...vWithSlugs,
versionEditUrl: editUrl:
'https://github.com/facebook/docusaurus/edit/main/website/versioned_docs/version-withSlugs', 'https://github.com/facebook/docusaurus/edit/main/website/versioned_docs/version-withSlugs',
versionEditUrlLocalized: editUrlLocalized:
'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/version-withSlugs', 'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/version-withSlugs',
}, },
]); ]);
@ -479,30 +481,30 @@ describe('readVersionsMetadata', () => {
expect(versionsMetadata).toEqual([ expect(versionsMetadata).toEqual([
{ {
...vCurrent, ...vCurrent,
versionEditUrl: editUrl:
'https://github.com/facebook/docusaurus/edit/main/website/docs', 'https://github.com/facebook/docusaurus/edit/main/website/docs',
versionEditUrlLocalized: editUrlLocalized:
'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/current', 'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/current',
}, },
{ {
...v101, ...v101,
versionEditUrl: editUrl:
'https://github.com/facebook/docusaurus/edit/main/website/docs', 'https://github.com/facebook/docusaurus/edit/main/website/docs',
versionEditUrlLocalized: editUrlLocalized:
'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/current', 'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/current',
}, },
{ {
...v100, ...v100,
versionEditUrl: editUrl:
'https://github.com/facebook/docusaurus/edit/main/website/docs', 'https://github.com/facebook/docusaurus/edit/main/website/docs',
versionEditUrlLocalized: editUrlLocalized:
'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/current', 'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/current',
}, },
{ {
...vWithSlugs, ...vWithSlugs,
versionEditUrl: editUrl:
'https://github.com/facebook/docusaurus/edit/main/website/docs', 'https://github.com/facebook/docusaurus/edit/main/website/docs',
versionEditUrlLocalized: editUrlLocalized:
'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/current', 'https://github.com/facebook/docusaurus/edit/main/website/i18n/en/docusaurus-plugin-content-docs/current',
}, },
]); ]);
@ -538,9 +540,9 @@ describe('readVersionsMetadata', () => {
isLast: true, isLast: true,
routePriority: -1, routePriority: -1,
tagsPath: '/docs/tags', tagsPath: '/docs/tags',
versionPath: '/docs', path: '/docs',
versionBanner: null, banner: null,
versionBadge: false, badge: false,
}, },
]); ]);
}); });
@ -679,12 +681,12 @@ describe('readVersionsMetadata', () => {
routePriority: undefined, routePriority: undefined,
sidebarFilePath: path.join(versionedSiteDir, 'sidebars.json'), sidebarFilePath: path.join(versionedSiteDir, 'sidebars.json'),
tagsPath: '/communityBasePath/next/tags', tagsPath: '/communityBasePath/next/tags',
versionLabel: 'Next', label: 'Next',
versionName: 'current', versionName: 'current',
versionPath: '/communityBasePath/next', path: '/communityBasePath/next',
versionBanner: 'unreleased', banner: 'unreleased',
versionBadge: true, badge: true,
versionClassName: 'docs-version-current', className: 'docs-version-current',
}; };
const v100: VersionMetadata = { const v100: VersionMetadata = {
@ -703,12 +705,12 @@ describe('readVersionsMetadata', () => {
'community_versioned_sidebars/version-1.0.0-sidebars.json', 'community_versioned_sidebars/version-1.0.0-sidebars.json',
), ),
tagsPath: '/communityBasePath/tags', tagsPath: '/communityBasePath/tags',
versionLabel: '1.0.0', label: '1.0.0',
versionName: '1.0.0', versionName: '1.0.0',
versionPath: '/communityBasePath', path: '/communityBasePath',
versionBanner: null, banner: null,
versionBadge: true, badge: true,
versionClassName: 'docs-version-1.0.0', className: 'docs-version-1.0.0',
}; };
return {versionedSiteDir, defaultOptions, defaultContext, vCurrent, v100}; return {versionedSiteDir, defaultOptions, defaultContext, vCurrent, v100};
@ -735,7 +737,7 @@ describe('readVersionsMetadata', () => {
expect(versionsMetadata).toEqual([ expect(versionsMetadata).toEqual([
// vCurrent removed // vCurrent removed
{...v100, versionBadge: false}, {...v100, badge: false},
]); ]);
}); });
@ -753,9 +755,9 @@ describe('readVersionsMetadata', () => {
isLast: true, isLast: true,
routePriority: -1, routePriority: -1,
tagsPath: '/communityBasePath/tags', tagsPath: '/communityBasePath/tags',
versionPath: '/communityBasePath', path: '/communityBasePath',
versionBanner: null, banner: null,
versionBadge: false, badge: false,
}, },
]); ]);
}); });

View file

@ -5,7 +5,10 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import type {CategoryGeneratedIndexMetadata, DocMetadataBase} from './types'; import type {
CategoryGeneratedIndexMetadata,
DocMetadataBase,
} from '@docusaurus/plugin-content-docs';
import type {SidebarItemCategoryWithGeneratedIndex} from './sidebars/types'; import type {SidebarItemCategoryWithGeneratedIndex} from './sidebars/types';
import {type SidebarsUtils, toNavigationLink} from './sidebars/utils'; import {type SidebarsUtils, toNavigationLink} from './sidebars/utils';
import {createDocsByIdIndex} from './docs'; import {createDocsByIdIndex} from './docs';
@ -29,8 +32,10 @@ function getCategoryGeneratedIndexMetadata({
slug: category.link.slug, slug: category.link.slug,
permalink: category.link.permalink, permalink: category.link.permalink,
sidebar: sidebarName!, sidebar: sidebarName!,
navigation: {
previous: toNavigationLink(previous, docsById), previous: toNavigationLink(previous, docsById),
next: toNavigationLink(next, docsById), next: toNavigationLink(next, docsById),
},
}; };
} }

View file

@ -12,6 +12,7 @@ import {
aliasedSitePath, aliasedSitePath,
getEditUrl, getEditUrl,
getFolderContainingFile, getFolderContainingFile,
getContentPathList,
normalizeUrl, normalizeUrl,
parseMarkdownString, parseMarkdownString,
posixPath, posixPath,
@ -21,18 +22,9 @@ import {
import type {LoadContext} from '@docusaurus/types'; import type {LoadContext} from '@docusaurus/types';
import {getFileLastUpdate} from './lastUpdate'; import {getFileLastUpdate} from './lastUpdate';
import type { import type {DocFile, LoadedVersion} from './types';
DocFile,
DocMetadataBase,
DocMetadata,
DocNavLink,
LastUpdateData,
VersionMetadata,
LoadedVersion,
} from './types';
import getSlug from './slug'; import getSlug from './slug';
import {CURRENT_VERSION_NAME} from './constants'; import {CURRENT_VERSION_NAME} from './constants';
import {getDocsDirPaths} from './versions';
import {stripPathNumberPrefixes} from './numberPrefix'; import {stripPathNumberPrefixes} from './numberPrefix';
import {validateDocFrontMatter} from './frontMatter'; import {validateDocFrontMatter} from './frontMatter';
import type {SidebarsUtils} from './sidebars/utils'; import type {SidebarsUtils} from './sidebars/utils';
@ -41,7 +33,11 @@ import type {
MetadataOptions, MetadataOptions,
PluginOptions, PluginOptions,
CategoryIndexMatcher, CategoryIndexMatcher,
CategoryIndexMatcherParam, DocMetadataBase,
DocMetadata,
PropNavigationLink,
LastUpdateData,
VersionMetadata,
} from '@docusaurus/plugin-content-docs'; } from '@docusaurus/plugin-content-docs';
type LastUpdateOptions = Pick< type LastUpdateOptions = Pick<
@ -85,7 +81,7 @@ export async function readDocFile(
options: LastUpdateOptions, options: LastUpdateOptions,
): Promise<DocFile> { ): Promise<DocFile> {
const contentPath = await getFolderContainingFile( const contentPath = await getFolderContainingFile(
getDocsDirPaths(versionMetadata), getContentPathList(versionMetadata),
source, source,
); );
@ -213,7 +209,7 @@ function doProcessDocMetadata({
const description: string = frontMatter.description ?? excerpt ?? ''; const description: string = frontMatter.description ?? excerpt ?? '';
const permalink = normalizeUrl([versionMetadata.versionPath, docSlug]); const permalink = normalizeUrl([versionMetadata.path, docSlug]);
function getDocEditUrl() { function getDocEditUrl() {
const relativeFilePath = path.relative(contentPath, filePath); const relativeFilePath = path.relative(contentPath, filePath);
@ -232,8 +228,8 @@ function doProcessDocMetadata({
const isLocalized = contentPath === versionMetadata.contentPathLocalized; const isLocalized = contentPath === versionMetadata.contentPathLocalized;
const baseVersionEditUrl = const baseVersionEditUrl =
isLocalized && options.editLocalizedFiles isLocalized && options.editLocalizedFiles
? versionMetadata.versionEditUrlLocalized ? versionMetadata.editUrlLocalized
: versionMetadata.versionEditUrl; : versionMetadata.editUrl;
return getEditUrl(relativeFilePath, baseVersionEditUrl); return getEditUrl(relativeFilePath, baseVersionEditUrl);
} }
return undefined; return undefined;
@ -304,7 +300,7 @@ export function addDocNavigation(
const toNavigationLinkByDocId = ( const toNavigationLinkByDocId = (
docId: string | null | undefined, docId: string | null | undefined,
type: 'prev' | 'next', type: 'prev' | 'next',
): DocNavLink | undefined => { ): PropNavigationLink | undefined => {
if (!docId) { if (!docId) {
return undefined; return undefined;
} }
@ -401,7 +397,7 @@ export function toCategoryIndexMatcherParam({
}: Pick< }: Pick<
DocMetadataBase, DocMetadataBase,
'source' | 'sourceDirName' 'source' | 'sourceDirName'
>): CategoryIndexMatcherParam { >): Parameters<CategoryIndexMatcher>[0] {
// source + sourceDirName are always posix-style // source + sourceDirName are always posix-style
return { return {
fileName: path.posix.parse(source).name, fileName: path.posix.parse(source).name,

View file

@ -12,7 +12,7 @@ import {
FrontMatterTOCHeadingLevels, FrontMatterTOCHeadingLevels,
validateFrontMatter, validateFrontMatter,
} from '@docusaurus/utils-validation'; } from '@docusaurus/utils-validation';
import type {DocFrontMatter} from './types'; import type {DocFrontMatter} from '@docusaurus/plugin-content-docs';
// NOTE: we don't add any default value on purpose here // NOTE: we don't add any default value on purpose here
// We don't want default values to magically appear in doc metadata and props // We don't want default values to magically appear in doc metadata and props

View file

@ -8,11 +8,11 @@
import _ from 'lodash'; import _ from 'lodash';
import type {Sidebars} from './sidebars/types'; import type {Sidebars} from './sidebars/types';
import {createSidebarsUtils} from './sidebars/utils'; import {createSidebarsUtils} from './sidebars/utils';
import type {LoadedVersion} from './types';
import type { import type {
CategoryGeneratedIndexMetadata, CategoryGeneratedIndexMetadata,
DocMetadata, DocMetadata,
LoadedVersion, } from '@docusaurus/plugin-content-docs';
} from './types';
import type { import type {
GlobalVersion, GlobalVersion,
GlobalSidebar, GlobalSidebar,
@ -65,9 +65,9 @@ function toGlobalSidebars(
export function toGlobalDataVersion(version: LoadedVersion): GlobalVersion { export function toGlobalDataVersion(version: LoadedVersion): GlobalVersion {
return { return {
name: version.versionName, name: version.versionName,
label: version.versionLabel, label: version.label,
isLast: version.isLast, isLast: version.isLast,
path: version.versionPath, path: version.path,
mainDocId: version.mainDocId, mainDocId: version.mainDocId,
docs: version.docs docs: version.docs
.map(toGlobalDataDoc) .map(toGlobalDataDoc)

View file

@ -11,6 +11,7 @@ import {
normalizeUrl, normalizeUrl,
docuHash, docuHash,
aliasedSitePath, aliasedSitePath,
getContentPathList,
reportMessage, reportMessage,
posixPath, posixPath,
addTrailingPathSeparator, addTrailingPathSeparator,
@ -27,18 +28,14 @@ import {
addDocNavigation, addDocNavigation,
getMainDocId, getMainDocId,
} from './docs'; } from './docs';
import {getDocsDirPaths, readVersionsMetadata} from './versions'; import {readVersionsMetadata} from './versions';
import type { import type {
LoadedContent, LoadedContent,
SourceToPermalink, SourceToPermalink,
DocMetadataBase,
VersionMetadata,
LoadedVersion, LoadedVersion,
DocFile, DocFile,
DocsMarkdownOption, DocsMarkdownOption,
VersionTag, VersionTag,
DocFrontMatter,
} from './types'; } from './types';
import type {RuleSetRule} from 'webpack'; import type {RuleSetRule} from 'webpack';
import {cliDocsVersionCommand} from './cli'; import {cliDocsVersionCommand} from './cli';
@ -55,6 +52,9 @@ import {createVersionRoutes} from './routes';
import type { import type {
PropTagsListPage, PropTagsListPage,
PluginOptions, PluginOptions,
DocMetadataBase,
VersionMetadata,
DocFrontMatter,
} from '@docusaurus/plugin-content-docs'; } from '@docusaurus/plugin-content-docs';
import {createSidebarsUtils} from './sidebars/utils'; import {createSidebarsUtils} from './sidebars/utils';
import {getCategoryGeneratedIndexMetadataList} from './categoryGeneratedIndex'; import {getCategoryGeneratedIndexMetadataList} from './categoryGeneratedIndex';
@ -114,7 +114,7 @@ export default async function pluginContentDocs(
function getVersionPathsToWatch(version: VersionMetadata): string[] { function getVersionPathsToWatch(version: VersionMetadata): string[] {
const result = [ const result = [
...options.include.flatMap((pattern) => ...options.include.flatMap((pattern) =>
getDocsDirPaths(version).map( getContentPathList(version).map(
(docsDirPath) => `${docsDirPath}/${pattern}`, (docsDirPath) => `${docsDirPath}/${pattern}`,
), ),
), ),
@ -228,7 +228,7 @@ export default async function pluginContentDocs(
const tagsProp: PropTagsListPage['tags'] = Object.values( const tagsProp: PropTagsListPage['tags'] = Object.values(
versionTags, versionTags,
).map((tagValue) => ({ ).map((tagValue) => ({
name: tagValue.name, name: tagValue.label,
permalink: tagValue.permalink, permalink: tagValue.permalink,
count: tagValue.docIds.length, count: tagValue.docIds.length,
})); }));
@ -331,7 +331,7 @@ export default async function pluginContentDocs(
}; };
function createMDXLoaderRule(): RuleSetRule { function createMDXLoaderRule(): RuleSetRule {
const contentDirs = versionsMetadata.flatMap(getDocsDirPaths); const contentDirs = versionsMetadata.flatMap(getContentPathList);
return { return {
test: /\.mdx?$/i, test: /\.mdx?$/i,
include: contentDirs include: contentDirs

View file

@ -12,9 +12,9 @@ import {linkify} from '../linkify';
import type { import type {
DocsMarkdownOption, DocsMarkdownOption,
SourceToPermalink, SourceToPermalink,
VersionMetadata,
DocBrokenMarkdownLink, DocBrokenMarkdownLink,
} from '../../types'; } from '../../types';
import type {VersionMetadata} from '@docusaurus/plugin-content-docs';
import {VERSIONED_DOCS_DIR, CURRENT_VERSION_NAME} from '../../constants'; import {VERSIONED_DOCS_DIR, CURRENT_VERSION_NAME} from '../../constants';
function createFakeVersion({ function createFakeVersion({

View file

@ -6,12 +6,11 @@
*/ */
import type {DocsMarkdownOption} from '../types'; import type {DocsMarkdownOption} from '../types';
import {getDocsDirPaths} from '../versions'; import {replaceMarkdownLinks, getContentPathList} from '@docusaurus/utils';
import {replaceMarkdownLinks} from '@docusaurus/utils';
function getVersion(filePath: string, options: DocsMarkdownOption) { function getVersion(filePath: string, options: DocsMarkdownOption) {
const versionFound = options.versionsMetadata.find((version) => const versionFound = options.versionsMetadata.find((version) =>
getDocsDirPaths(version).some((docsDirPath) => getContentPathList(version).some((docsDirPath) =>
filePath.startsWith(docsDirPath), filePath.startsWith(docsDirPath),
), ),
); );

View file

@ -6,18 +6,25 @@
*/ */
declare module '@docusaurus/plugin-content-docs' { declare module '@docusaurus/plugin-content-docs' {
import type {RemarkAndRehypePluginOptions} from '@docusaurus/mdx-loader'; import type {MDXOptions} from '@docusaurus/mdx-loader';
import type {ContentPaths, Tag, FrontMatterTag} from '@docusaurus/utils';
import type {Required} from 'utility-types';
export interface Assets { export interface Assets {
image?: string; image?: string;
} }
/**
* Custom callback for parsing number prefixes from file/folder names.
*/
export type NumberPrefixParser = (filename: string) => { export type NumberPrefixParser = (filename: string) => {
/** file name without number prefix, without any other modification. */
filename: string; filename: string;
/** The number prefix. Can be float, integer, negative, or anything. */
numberPrefix?: number; numberPrefix?: number;
}; };
export type CategoryIndexMatcherParam = { export type CategoryIndexMatcher = (param: {
/** The file name, without extension */ /** The file name, without extension */
fileName: string; fileName: string;
/** /**
@ -27,110 +34,442 @@ declare module '@docusaurus/plugin-content-docs' {
directories: string[]; directories: string[];
/** The extension, with a leading dot */ /** The extension, with a leading dot */
extension: string; extension: string;
}; }) => boolean;
export type CategoryIndexMatcher = (
param: CategoryIndexMatcherParam,
) => boolean;
export type EditUrlFunction = (editUrlParams: { export type EditUrlFunction = (editUrlParams: {
/** Name of the version. */
version: string; version: string;
/**
* Path of the version's root content path, relative to the site directory.
* Usually the same as `options.path` but can be localized or versioned.
*/
versionDocsDirPath: string; versionDocsDirPath: string;
/** Path of the doc file, relative to `versionDocsDirPath`. */
docPath: string; docPath: string;
/** @see {@link DocMetadata.permalink} */
permalink: string; permalink: string;
/** Locale name. */
locale: string; locale: string;
}) => string | undefined; }) => string | undefined;
export type MetadataOptions = { export type MetadataOptions = {
/**
* URL route for the docs section of your site. **DO NOT** include a
* trailing slash. Use `/` for shipping docs without base path.
*/
routeBasePath: string; routeBasePath: string;
/**
* Base URL to edit your site. The final URL is computed by `editUrl +
* relativeDocPath`. Using a function allows more nuanced control for each
* file. Omitting this variable entirely will disable edit links.
*/
editUrl?: string | EditUrlFunction; editUrl?: string | EditUrlFunction;
/**
* The edit URL will always target the current version doc instead of older
* versions. Ignored when `editUrl` is a function.
*/
editCurrentVersion: boolean; editCurrentVersion: boolean;
/**
* The edit URL will target the localized file, instead of the original
* unlocalized file. Ignored when `editUrl` is a function.
*/
editLocalizedFiles: boolean; editLocalizedFiles: boolean;
/** Whether to display the last date the doc was updated. */
showLastUpdateTime?: boolean; showLastUpdateTime?: boolean;
/** Whether to display the author who last updated the doc. */
showLastUpdateAuthor?: boolean; showLastUpdateAuthor?: boolean;
/**
* Custom parsing logic to extract number prefixes from file names. Use
* `false` to disable this behavior and leave the docs untouched, and `true`
* to use the default parser.
*
* @param filename One segment of the path, without any slashes.
* @see https://docusaurus.io/docs/sidebar#using-number-prefixes
*/
numberPrefixParser: NumberPrefixParser; numberPrefixParser: NumberPrefixParser;
/** Enable or disable the breadcrumbs on doc pages. */
breadcrumbs: boolean; breadcrumbs: boolean;
}; };
export type PathOptions = { export type PathOptions = {
/**
* Path to the docs content directory on the file system, relative to site
* directory.
*/
path: string; path: string;
/**
* Path to sidebar configuration. Use `false` to disable sidebars, or
* `undefined` to create a fully autogenerated sidebar.
*/
sidebarPath?: string | false | undefined; sidebarPath?: string | false | undefined;
}; };
// TODO support custom version banner? // TODO support custom version banner?
// {type: "error", content: "html content"} // {type: "error", content: "html content"}
export type VersionBanner = 'unreleased' | 'unmaintained'; export type VersionBanner = 'unreleased' | 'unmaintained';
export type VersionOptions = { export type VersionsOptions = {
/**
* The version navigated to in priority and displayed by default for docs
* navbar items.
*
* @see https://docusaurus.io/docs/versioning#terminology
*/
lastVersion?: string;
/** Only include a subset of all available versions. */
onlyIncludeVersions?: string[];
/**
* Explicitly disable versioning even when multiple versions exist. This
* will make the site only include the current version. Will error if
* `includeCurrentVersion: false` and `disableVersioning: true`.
*/
disableVersioning: boolean;
/** Include the current version of your docs. */
includeCurrentVersion: boolean;
/** Independent customization of each version's properties. */
versions: {
[versionName: string]: {
/**
* The base path of the version, will be appended to `baseUrl` +
* `routeBasePath`.
*/
path?: string; path?: string;
/** The label of the version to be used in badges, dropdowns, etc. */
label?: string; label?: string;
/** The banner to show at the top of a doc of that version. */
banner?: 'none' | VersionBanner; banner?: 'none' | VersionBanner;
/** Show a badge with the version label at the top of each doc. */
badge?: boolean; badge?: boolean;
/** Add a custom class name to the <html> element of each doc. */
className?: string; className?: string;
}; };
export type VersionsOptions = { };
lastVersion?: string;
versions: {[versionName: string]: VersionOptions};
onlyIncludeVersions?: string[];
}; };
export type SidebarOptions = { export type SidebarOptions = {
/**
* Whether sidebar categories are collapsible by default.
*
* @see https://docusaurus.io/docs/sidebar#collapsible-categories
*/
sidebarCollapsible: boolean; sidebarCollapsible: boolean;
/**
* Whether sidebar categories are collapsed by default.
*
* @see https://docusaurus.io/docs/sidebar#expanded-categories-by-default
*/
sidebarCollapsed: boolean; sidebarCollapsed: boolean;
}; };
export type PluginOptions = MetadataOptions & export type PluginOptions = MetadataOptions &
PathOptions & PathOptions &
VersionsOptions & VersionsOptions &
RemarkAndRehypePluginOptions & MDXOptions &
SidebarOptions & { SidebarOptions & {
/** Plugin ID. */
id: string; id: string;
/**
* Array of glob patterns matching Markdown files to be built, relative to
* the content path.
*/
include: string[]; include: string[];
/**
* Array of glob patterns matching Markdown files to be excluded. Serves
* as refinement based on the `include` option.
*/
exclude: string[]; exclude: string[];
/**
* Root layout component of each doc page. Provides the version data
* context, and is not unmounted when switching docs.
*/
docLayoutComponent: string; docLayoutComponent: string;
/** Main doc container, with TOC, pagination, etc. */
docItemComponent: string; docItemComponent: string;
/** Root component of the "docs containing tag X" page. */
docTagDocListComponent: string; docTagDocListComponent: string;
/** Root component of the tags list page */
docTagsListComponent: string; docTagsListComponent: string;
/** Root component of the generated category index page. */
docCategoryGeneratedIndexComponent: string; docCategoryGeneratedIndexComponent: string;
admonitions: {[key: string]: unknown}; admonitions: {[key: string]: unknown};
disableVersioning: boolean;
includeCurrentVersion: boolean;
sidebarItemsGenerator: import('./sidebars/types').SidebarItemsGeneratorOption; sidebarItemsGenerator: import('./sidebars/types').SidebarItemsGeneratorOption;
/**
* URL route for the tags section of your doc version. Will be appended to
* `routeBasePath`. **DO NOT** include a trailing slash.
*/
tagsBasePath: string; tagsBasePath: string;
}; };
export type Options = Partial<PluginOptions>; export type Options = Partial<PluginOptions>;
export type SidebarsConfig = import('./sidebars/types').SidebarsConfig; export type SidebarsConfig = import('./sidebars/types').SidebarsConfig;
export type VersionMetadata = ContentPaths & {
/** A name like `1.0.0`. Acquired from `versions.json`. */
versionName: string;
/** Like `Version 1.0.0`. Can be configured through `versions.label`. */
label: string;
/**
* Version's base path in the form of `/<baseUrl>/<routeBasePath>/1.0.0`.
* Can be configured through `versions.path`.
*/
path: string;
/** Tags base path in the form of `<versionPath>/tags`. */
tagsPath: string;
/**
* The base URL to which the doc file path will be appended. Will be
* `undefined` if `editUrl` is `undefined` or a function.
*/
editUrl?: string | undefined;
/**
* The base URL to which the localized doc file path will be appended. Will
* be `undefined` if `editUrl` is `undefined` or a function.
*/
editUrlLocalized?: string | undefined;
/**
* "unmaintained" is the version before latest; "unreleased" is the version
* after latest. `null` is the latest version without a banner. Can be
* configured with `versions.banner`: `banner: "none"` will be transformed
* to `null` here.
*/
banner: VersionBanner | null;
/** Show a badge with the version label at the top of each doc. */
badge: boolean;
/** Add a custom class name to the <html> element of each doc. */
className: string;
/**
* Whether this version is the "last" version. Can be configured with
* `lastVersion` option.
*/
isLast: boolean;
/**
* Like `versioned_sidebars/1.0.0.json`. Versioned sidebars file may be
* nonexistent since we don't create empty files.
*/
sidebarFilePath: string | false | undefined;
/**
* Will be -1 for the latest docs, and `undefined` for everything else.
* Because `/docs/foo` should always be after `/docs/<versionName>/foo`.
*/
routePriority: number | undefined;
};
export type DocFrontMatter = {
/**
* The last part of the doc ID (will be refactored in the future to be the
* full ID instead)
* @see {@link DocMetadata.id}
*/
id?: string;
/**
* Will override the default title collected from h1 heading.
* @see {@link DocMetadata.title}
*/
title?: string;
/**
* Front matter tags, unnormalized.
* @see {@link DocMetadata.tags}
*/
tags?: FrontMatterTag[];
/**
* If there isn't a Markdown h1 heading (which, if there is, we don't
* remove), this front matter will cause the front matter title to not be
* displayed in the doc page.
*/
hide_title?: boolean;
/** Hide the TOC on the right. */
hide_table_of_contents?: boolean;
/** Used in the head meta. */
keywords?: string[];
/** Used in the head meta. Should use `assets.image` in priority. */
image?: string;
/**
* Will override the default excerpt.
* @see {@link DocMetadata.description}
*/
description?: string;
/**
* Custom slug appended after /<baseUrl>/<routeBasePath>/<versionPath>
* @see {@link DocMetadata.slug}
*/
slug?: string;
/** Customizes the sidebar label for this doc. Will default to its title. */
sidebar_label?: string;
/**
* Controls the position of a doc inside the generated sidebar slice when
* using autogenerated sidebar items.
*
* @see https://docusaurus.io/docs/sidebar#autogenerated-sidebar-metadata
*/
sidebar_position?: number;
/**
* Gives the corresponding sidebar label a special class name when using
* autogenerated sidebars.
*/
sidebar_class_name?: string;
/**
* Will be propagated to the final sidebars data structure. Useful if you
* have swizzled sidebar-related code or simply querying doc data through
* sidebars.
*/
sidebar_custom_props?: {[key: string]: unknown};
/**
* Changes the sidebar association of the current doc. Use `null` to make
* the current doc not associated to any sidebar.
*/
displayed_sidebar?: string | null;
/**
* Customizes the pagination label for this doc. Will default to the sidebar
* label.
*/
pagination_label?: string;
/** Overrides the default URL computed for this doc. */
custom_edit_url?: string | null;
/**
* Whether number prefix parsing is disabled on this doc.
* @see https://docusaurus.io/docs/sidebar#using-number-prefixes
*/
parse_number_prefixes?: boolean;
/**
* Minimum TOC heading level. Must be between 2 and 6 and lower or equal to
* the max value.
*/
toc_min_heading_level?: number;
/** Maximum TOC heading level. Must be between 2 and 6. */
toc_max_heading_level?: number;
/**
* The ID of the documentation you want the "Next" pagination to link to.
* Use `null` to disable showing "Next" for this page.
* @see {@link DocMetadata.next}
*/
pagination_next?: string | null;
/**
* The ID of the documentation you want the "Previous" pagination to link
* to. Use `null` to disable showing "Previous" for this page.
* @see {@link DocMetadata.prev}
*/
pagination_prev?: string | null;
};
export type LastUpdateData = {
/** A timestamp in **seconds**, directly acquired from `git log`. */
lastUpdatedAt?: number;
/** `lastUpdatedAt` formatted as a date according to the current locale. */
formattedLastUpdatedAt?: string;
/** The author's name directly acquired from `git log`. */
lastUpdatedBy?: string;
};
export type DocMetadataBase = LastUpdateData & {
// TODO
/**
* Legacy versioned ID. Will be refactored in the future to be unversioned.
*/
id: string;
// TODO
/**
* Unversioned ID. Should be preferred everywhere over `id` until the latter
* is refactored.
*/
unversionedId: string;
/** The name of the version this doc belongs to. */
version: string;
/**
* Used to generate the page h1 heading, tab title, and pagination title.
*/
title: string;
/**
* Description used in the meta. Could be an empty string (empty content)
*/
description: string;
/** Path to the Markdown source, with `@site` alias. */
source: string;
/**
* Posix path relative to the content path. Can be `"."`.
* e.g. "folder/subfolder/subsubfolder"
*/
sourceDirName: string;
/** `permalink` without base URL or version path. */
slug: string;
/** Full URL to this doc, with base URL and version path. */
permalink: string;
/**
* Position in an autogenerated sidebar slice, acquired through front matter
* or number prefix.
*/
sidebarPosition?: number;
/**
* Acquired from the options; can be customized with front matter.
* `custom_edit_url` will always lead to it being null, but you should treat
* `undefined` and `null` as equivalent.
*/
editUrl?: string | null;
/** Tags, normalized. */
tags: Tag[];
/** Front matter, as-is. */
frontMatter: DocFrontMatter & {[key: string]: unknown};
};
export type DocMetadata = DocMetadataBase &
PropNavigation & {
/** Name of the sidebar this doc is associated with. */
sidebar?: string;
};
export type CategoryGeneratedIndexMetadata = Required<
Omit<
import('./sidebars/types').SidebarItemCategoryLinkGeneratedIndex,
'type'
>,
'title'
> & {
navigation: PropNavigation;
/**
* Name of the sidebar this doc is associated with. Unlike
* `DocMetadata.sidebar`, this will always be defined, because a generated
* index can only be generated from a category.
*/
sidebar: string;
};
export type PropNavigationLink = { export type PropNavigationLink = {
readonly title: string; readonly title: string;
readonly permalink: string; readonly permalink: string;
}; };
export type PropNavigation = { export type PropNavigation = {
/**
* Used in pagination. Content is just a subset of another doc's metadata.
*/
readonly previous?: PropNavigationLink; readonly previous?: PropNavigationLink;
/**
* Used in pagination. Content is just a subset of another doc's metadata.
*/
readonly next?: PropNavigationLink; readonly next?: PropNavigationLink;
}; };
export type PropVersionDoc = import('./sidebars/types').PropVersionDoc; export type PropVersionDoc = Pick<
export type PropVersionDocs = import('./sidebars/types').PropVersionDocs; DocMetadata,
'id' | 'title' | 'description' | 'sidebar'
>;
export type PropVersionMetadata = { export type PropVersionDocs = {
[docId: string]: PropVersionDoc;
};
export type PropVersionMetadata = Pick<
VersionMetadata,
'label' | 'banner' | 'badge' | 'className' | 'isLast'
> & {
/** ID of the docs plugin this version belongs to. */
pluginId: string; pluginId: string;
/** Name of this version. */
version: string; version: string;
label: string; /** Sidebars contained in this version. */
banner: VersionBanner | null;
badge: boolean;
className: string;
isLast: boolean;
docsSidebars: PropSidebars; docsSidebars: PropSidebars;
/** Docs contained in this version. */
docs: PropVersionDocs; docs: PropVersionDocs;
}; };
export type PropCategoryGeneratedIndex = { export type PropCategoryGeneratedIndex = Omit<
title: string; CategoryGeneratedIndexMetadata,
description?: string; 'sidebar'
image?: string; >;
keywords?: string | readonly string[];
slug: string;
permalink: string;
navigation: PropNavigation;
};
export type PropSidebarItemLink = export type PropSidebarItemLink =
import('./sidebars/types').PropSidebarItemLink; import('./sidebars/types').PropSidebarItemLink;
@ -169,9 +508,10 @@ declare module '@docusaurus/plugin-content-docs' {
declare module '@theme/DocItem' { declare module '@theme/DocItem' {
import type {TOCItem} from '@docusaurus/types'; import type {TOCItem} from '@docusaurus/types';
import type { import type {
PropNavigationLink,
PropVersionMetadata, PropVersionMetadata,
Assets, Assets,
DocMetadata,
DocFrontMatter,
} from '@docusaurus/plugin-content-docs'; } from '@docusaurus/plugin-content-docs';
export type DocumentRoute = { export type DocumentRoute = {
@ -181,41 +521,12 @@ declare module '@theme/DocItem' {
readonly sidebar?: string; readonly sidebar?: string;
}; };
export type FrontMatter = {
readonly id: string;
readonly title: string;
readonly image?: string;
readonly keywords?: readonly string[];
readonly hide_title?: boolean;
readonly hide_table_of_contents?: boolean;
readonly toc_min_heading_level?: number;
readonly toc_max_heading_level?: number;
};
export type Metadata = {
readonly unversionedId?: string;
readonly description?: string;
readonly title?: string;
readonly permalink?: string;
readonly editUrl?: string;
readonly lastUpdatedAt?: number;
readonly formattedLastUpdatedAt?: string;
readonly lastUpdatedBy?: string;
readonly version?: string;
readonly previous?: PropNavigationLink;
readonly next?: PropNavigationLink;
readonly tags: readonly {
readonly label: string;
readonly permalink: string;
}[];
};
export interface Props { export interface Props {
readonly route: DocumentRoute; readonly route: DocumentRoute;
readonly versionMetadata: PropVersionMetadata; readonly versionMetadata: PropVersionMetadata;
readonly content: { readonly content: {
readonly frontMatter: FrontMatter; readonly frontMatter: DocFrontMatter;
readonly metadata: Metadata; readonly metadata: DocMetadata;
readonly toc: readonly TOCItem[]; readonly toc: readonly TOCItem[];
readonly contentTitle: string | undefined; readonly contentTitle: string | undefined;
readonly assets: Assets; readonly assets: Assets;

View file

@ -5,13 +5,12 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import type {LoadedVersion, VersionTag, DocMetadata} from './types'; import type {LoadedVersion, VersionTag} from './types';
import type { import type {
SidebarItemDoc, SidebarItemDoc,
SidebarItem, SidebarItem,
SidebarItemCategory, SidebarItemCategory,
SidebarItemCategoryLink, SidebarItemCategoryLink,
PropVersionDocs,
} from './sidebars/types'; } from './sidebars/types';
import type { import type {
PropSidebars, PropSidebars,
@ -21,6 +20,8 @@ import type {
PropTagDocList, PropTagDocList,
PropTagDocListDoc, PropTagDocListDoc,
PropSidebarItemLink, PropSidebarItemLink,
PropVersionDocs,
DocMetadata,
} from '@docusaurus/plugin-content-docs'; } from '@docusaurus/plugin-content-docs';
import _ from 'lodash'; import _ from 'lodash';
import {createDocsByIdIndex} from './docs'; import {createDocsByIdIndex} from './docs';
@ -119,10 +120,10 @@ export function toVersionMetadataProp(
return { return {
pluginId, pluginId,
version: loadedVersion.versionName, version: loadedVersion.versionName,
label: loadedVersion.versionLabel, label: loadedVersion.label,
banner: loadedVersion.versionBanner, banner: loadedVersion.banner,
badge: loadedVersion.versionBadge, badge: loadedVersion.badge,
className: loadedVersion.versionClassName, className: loadedVersion.className,
isLast: loadedVersion.isLast, isLast: loadedVersion.isLast,
docsSidebars: toSidebarsProp(loadedVersion), docsSidebars: toSidebarsProp(loadedVersion),
docs: toVersionDocsProp(loadedVersion), docs: toVersionDocsProp(loadedVersion),
@ -153,7 +154,7 @@ export function toTagDocListProp({
} }
return { return {
name: tag.name, name: tag.label,
permalink: tag.permalink, permalink: tag.permalink,
docs: toDocListProp(), docs: toDocListProp(),
allTagsPath, allTagsPath,

View file

@ -7,12 +7,11 @@
import type {PluginContentLoadedActions, RouteConfig} from '@docusaurus/types'; import type {PluginContentLoadedActions, RouteConfig} from '@docusaurus/types';
import {docuHash, createSlugger} from '@docusaurus/utils'; import {docuHash, createSlugger} from '@docusaurus/utils';
import type {LoadedVersion} from './types';
import type { import type {
CategoryGeneratedIndexMetadata, CategoryGeneratedIndexMetadata,
DocMetadata, DocMetadata,
LoadedVersion, } from '@docusaurus/plugin-content-docs';
} from './types';
import type {PropCategoryGeneratedIndex} from '@docusaurus/plugin-content-docs';
import {toVersionMetadataProp} from './props'; import {toVersionMetadataProp} from './props';
import logger from '@docusaurus/logger'; import logger from '@docusaurus/logger';
@ -32,42 +31,19 @@ export async function createCategoryGeneratedIndexRoutes({
async function createCategoryGeneratedIndexRoute( async function createCategoryGeneratedIndexRoute(
categoryGeneratedIndex: CategoryGeneratedIndexMetadata, categoryGeneratedIndex: CategoryGeneratedIndexMetadata,
): Promise<RouteConfig> { ): Promise<RouteConfig> {
const { const {sidebar, ...prop} = categoryGeneratedIndex;
sidebar,
title,
description,
slug,
permalink,
previous,
next,
image,
keywords,
} = categoryGeneratedIndex;
const propFileName = slugs.slug( const propFileName = slugs.slug(
`${version.versionPath}-${categoryGeneratedIndex.sidebar}-category-${categoryGeneratedIndex.title}`, `${version.path}-${categoryGeneratedIndex.sidebar}-category-${categoryGeneratedIndex.title}`,
); );
const prop: PropCategoryGeneratedIndex = {
title,
description,
slug,
permalink,
image,
keywords,
navigation: {
previous,
next,
},
};
const propData = await actions.createData( const propData = await actions.createData(
`${docuHash(`category/${propFileName}`)}.json`, `${docuHash(`category/${propFileName}`)}.json`,
JSON.stringify(prop, null, 2), JSON.stringify(prop, null, 2),
); );
return { return {
path: permalink, path: categoryGeneratedIndex.permalink,
component: docCategoryGeneratedIndexComponent, component: docCategoryGeneratedIndexComponent,
exact: true, exact: true,
modules: { modules: {
@ -162,7 +138,7 @@ export async function createVersionRoutes({
} }
actions.addRoute({ actions.addRoute({
path: version.versionPath, path: version.path,
// allow matching /docs/* as well // allow matching /docs/* as well
exact: false, exact: false,
// main docs component (DocPage) // main docs component (DocPage)

View file

@ -34,7 +34,7 @@ describe('postProcess', () => {
}, },
{ {
sidebarOptions: {sidebarCollapsed: true, sidebarCollapsible: true}, sidebarOptions: {sidebarCollapsed: true, sidebarCollapsible: true},
version: {versionPath: 'version'}, version: {path: 'version'},
}, },
); );
@ -53,7 +53,7 @@ describe('postProcess', () => {
}, },
{ {
sidebarOptions: {sidebarCollapsed: true, sidebarCollapsible: true}, sidebarOptions: {sidebarCollapsed: true, sidebarCollapsible: true},
version: {versionPath: 'version'}, version: {path: 'version'},
}, },
); );
}).toThrowErrorMatchingInlineSnapshot( }).toThrowErrorMatchingInlineSnapshot(
@ -78,7 +78,7 @@ describe('postProcess', () => {
{ {
sidebarOptions: {sidebarCollapsed: true, sidebarCollapsible: true}, sidebarOptions: {sidebarCollapsed: true, sidebarCollapsible: true},
version: {versionPath: 'version'}, version: {path: 'version'},
}, },
), ),
).toMatchSnapshot(); ).toMatchSnapshot();
@ -98,7 +98,7 @@ describe('postProcess', () => {
{ {
sidebarOptions: {sidebarCollapsed: false, sidebarCollapsible: false}, sidebarOptions: {sidebarCollapsed: false, sidebarCollapsible: false},
version: {versionPath: 'version'}, version: {path: 'version'},
}, },
), ),
).toMatchSnapshot(); ).toMatchSnapshot();
@ -117,7 +117,7 @@ describe('postProcess', () => {
{ {
sidebarOptions: {sidebarCollapsed: true, sidebarCollapsible: false}, sidebarOptions: {sidebarCollapsed: true, sidebarCollapsible: false},
version: {versionPath: 'version'}, version: {path: 'version'},
}, },
), ),
).toMatchSnapshot(); ).toMatchSnapshot();

View file

@ -18,7 +18,7 @@ import type {
} from '../types'; } from '../types';
import {DefaultSidebarItemsGenerator} from '../generator'; import {DefaultSidebarItemsGenerator} from '../generator';
import {createSlugger} from '@docusaurus/utils'; import {createSlugger} from '@docusaurus/utils';
import type {VersionMetadata} from '../../types'; import type {VersionMetadata} from '@docusaurus/plugin-content-docs';
import {DefaultNumberPrefixParser} from '../../numberPrefix'; import {DefaultNumberPrefixParser} from '../../numberPrefix';
import {isCategoryIndex} from '../../docs'; import {isCategoryIndex} from '../../docs';

View file

@ -16,7 +16,10 @@ import {
toNavigationLink, toNavigationLink,
} from '../utils'; } from '../utils';
import type {Sidebar, Sidebars} from '../types'; import type {Sidebar, Sidebars} from '../types';
import type {DocMetadataBase, DocNavLink} from '../../types'; import type {
DocMetadataBase,
PropNavigationLink,
} from '@docusaurus/plugin-content-docs';
describe('createSidebarsUtils', () => { describe('createSidebarsUtils', () => {
const sidebar1: Sidebar = [ const sidebar1: Sidebar = [
@ -618,7 +621,7 @@ describe('toDocNavigationLink', () => {
).toEqual({ ).toEqual({
title: 'Doc Title', title: 'Doc Title',
permalink: '/docPermalink', permalink: '/docPermalink',
} as DocNavLink); } as PropNavigationLink);
}); });
it('with pagination_label front matter', () => { it('with pagination_label front matter', () => {
@ -635,7 +638,7 @@ describe('toDocNavigationLink', () => {
).toEqual({ ).toEqual({
title: 'pagination_label', title: 'pagination_label',
permalink: '/docPermalink', permalink: '/docPermalink',
} as DocNavLink); } as PropNavigationLink);
}); });
it('with sidebar_label front matter', () => { it('with sidebar_label front matter', () => {
@ -652,7 +655,7 @@ describe('toDocNavigationLink', () => {
).toEqual({ ).toEqual({
title: 'sidebar_label', title: 'sidebar_label',
permalink: '/docPermalink', permalink: '/docPermalink',
} as DocNavLink); } as PropNavigationLink);
}); });
it('with pagination_label + sidebar_label front matter', () => { it('with pagination_label + sidebar_label front matter', () => {
@ -670,7 +673,7 @@ describe('toDocNavigationLink', () => {
).toEqual({ ).toEqual({
title: 'pagination_label', title: 'pagination_label',
permalink: '/docPermalink', permalink: '/docPermalink',
} as DocNavLink); } as PropNavigationLink);
}); });
}); });

View file

@ -26,7 +26,7 @@ function normalizeCategoryLink(
const getDefaultSlug = () => const getDefaultSlug = () =>
`/category/${params.categoryLabelSlugger.slug(category.label)}`; `/category/${params.categoryLabelSlugger.slug(category.label)}`;
const slug = category.link.slug ?? getDefaultSlug(); const slug = category.link.slug ?? getDefaultSlug();
const permalink = normalizeUrl([params.version.versionPath, slug]); const permalink = normalizeUrl([params.version.path, slug]);
return { return {
...category.link, ...category.link,
slug, slug,

View file

@ -5,7 +5,10 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import type {DocMetadataBase, VersionMetadata} from '../types'; import type {
DocMetadataBase,
VersionMetadata,
} from '@docusaurus/plugin-content-docs';
import type { import type {
NormalizedSidebarItem, NormalizedSidebarItem,
NormalizedSidebar, NormalizedSidebar,

View file

@ -6,11 +6,12 @@
*/ */
import type {Optional, Required} from 'utility-types'; import type {Optional, Required} from 'utility-types';
import type {DocMetadataBase, VersionMetadata} from '../types';
import type { import type {
NumberPrefixParser, NumberPrefixParser,
SidebarOptions, SidebarOptions,
CategoryIndexMatcher, CategoryIndexMatcher,
DocMetadataBase,
VersionMetadata,
} from '@docusaurus/plugin-content-docs'; } from '@docusaurus/plugin-content-docs';
import type {Slugger} from '@docusaurus/utils'; import type {Slugger} from '@docusaurus/utils';
@ -199,16 +200,6 @@ export type PropSidebarBreadcrumbsItem =
| PropSidebarItemLink | PropSidebarItemLink
| PropSidebarItemCategory; | PropSidebarItemCategory;
export type PropVersionDoc = {
id: string;
title: string;
description?: string;
sidebar?: string;
};
export type PropVersionDocs = {
[docId: string]: PropVersionDoc;
};
export type CategoryMetadataFile = { export type CategoryMetadataFile = {
label?: string; label?: string;
position?: number; position?: number;
@ -243,11 +234,20 @@ export type SidebarItemsGeneratorVersion = Pick<
>; >;
export type SidebarItemsGeneratorArgs = { export type SidebarItemsGeneratorArgs = {
/** The sidebar item with type "autogenerated" to be transformed. */
item: SidebarItemAutogenerated; item: SidebarItemAutogenerated;
/** Useful metadata for the version this sidebar belongs to. */
version: SidebarItemsGeneratorVersion; version: SidebarItemsGeneratorVersion;
/** All the docs of that version (unfiltered). */
docs: SidebarItemsGeneratorDoc[]; docs: SidebarItemsGeneratorDoc[];
/** Number prefix parser configured for this plugin. */
numberPrefixParser: NumberPrefixParser; numberPrefixParser: NumberPrefixParser;
/** The default category index matcher which you can override. */
isCategoryIndex: CategoryIndexMatcher; isCategoryIndex: CategoryIndexMatcher;
/**
* key is the path relative to the doc content directory, value is the
* category metadata file's content.
*/
categoriesMetadata: {[filePath: string]: CategoryMetadataFile}; categoriesMetadata: {[filePath: string]: CategoryMetadataFile};
}; };
export type SidebarItemsGenerator = ( export type SidebarItemsGenerator = (
@ -258,6 +258,10 @@ export type SidebarItemsGenerator = (
// default sidebar gen logic // default sidebar gen logic
// see https://github.com/facebook/docusaurus/issues/4640#issuecomment-822292320 // see https://github.com/facebook/docusaurus/issues/4640#issuecomment-822292320
export type SidebarItemsGeneratorOptionArgs = { export type SidebarItemsGeneratorOptionArgs = {
/**
* Useful to re-use/enhance the default sidebar generation logic from
* Docusaurus.
*/
defaultSidebarItemsGenerator: SidebarItemsGenerator; defaultSidebarItemsGenerator: SidebarItemsGenerator;
} & SidebarItemsGeneratorArgs; } & SidebarItemsGeneratorArgs;
export type SidebarItemsGeneratorOption = ( export type SidebarItemsGeneratorOption = (

View file

@ -21,7 +21,10 @@ import type {
import _ from 'lodash'; import _ from 'lodash';
import {toMessageRelativeFilePath} from '@docusaurus/utils'; import {toMessageRelativeFilePath} from '@docusaurus/utils';
import type {DocMetadataBase, DocNavLink} from '../types'; import type {
DocMetadataBase,
PropNavigationLink,
} from '@docusaurus/plugin-content-docs';
export function isCategoriesShorthand( export function isCategoriesShorthand(
item: SidebarItemConfig, item: SidebarItemConfig,
@ -346,7 +349,7 @@ Available document ids are:
}; };
} }
export function toDocNavigationLink(doc: DocMetadataBase): DocNavLink { export function toDocNavigationLink(doc: DocMetadataBase): PropNavigationLink {
const { const {
title, title,
permalink, permalink,
@ -361,7 +364,7 @@ export function toDocNavigationLink(doc: DocMetadataBase): DocNavLink {
export function toNavigationLink( export function toNavigationLink(
navigationItem: SidebarNavigationItem | undefined, navigationItem: SidebarNavigationItem | undefined,
docsById: {[docId: string]: DocMetadataBase}, docsById: {[docId: string]: DocMetadataBase},
): DocNavLink | undefined { ): PropNavigationLink | undefined {
function getDocById(docId: string) { function getDocById(docId: string) {
const doc = docsById[docId]; const doc = docsById[docId];
if (!doc) { if (!doc) {

View file

@ -15,9 +15,11 @@ import {
DefaultNumberPrefixParser, DefaultNumberPrefixParser,
stripPathNumberPrefixes, stripPathNumberPrefixes,
} from './numberPrefix'; } from './numberPrefix';
import type {DocMetadataBase} from './types';
import {isCategoryIndex, toCategoryIndexMatcherParam} from './docs'; import {isCategoryIndex, toCategoryIndexMatcherParam} from './docs';
import type {NumberPrefixParser} from '@docusaurus/plugin-content-docs'; import type {
NumberPrefixParser,
DocMetadataBase,
} from '@docusaurus/plugin-content-docs';
export default function getSlug({ export default function getSlug({
baseID, baseID,

View file

@ -6,13 +6,14 @@
*/ */
import {groupTaggedItems} from '@docusaurus/utils'; import {groupTaggedItems} from '@docusaurus/utils';
import type {VersionTags, DocMetadata} from './types'; import type {VersionTags} from './types';
import type {DocMetadata} from '@docusaurus/plugin-content-docs';
import _ from 'lodash'; import _ from 'lodash';
export function getVersionTags(docs: DocMetadata[]): VersionTags { export function getVersionTags(docs: DocMetadata[]): VersionTags {
const groups = groupTaggedItems(docs, (doc) => doc.tags); const groups = groupTaggedItems(docs, (doc) => doc.tags);
return _.mapValues(groups, (group) => ({ return _.mapValues(groups, (group) => ({
name: group.tag.label, label: group.tag.label,
docIds: group.items.map((item) => item.id), docIds: group.items.map((item) => item.id),
permalink: group.tag.permalink, permalink: group.tag.permalink,
})); }));

View file

@ -245,7 +245,7 @@ function translateSidebars(
function getVersionTranslationFiles(version: LoadedVersion): TranslationFiles { function getVersionTranslationFiles(version: LoadedVersion): TranslationFiles {
const versionTranslations: TranslationFileContent = { const versionTranslations: TranslationFileContent = {
'version.label': { 'version.label': {
message: version.versionLabel, message: version.label,
description: `The label for version ${version.versionName}`, description: `The label for version ${version.versionName}`,
}, },
}; };
@ -275,8 +275,7 @@ function translateVersion(
translationFiles[getVersionFileName(version.versionName)]!.content; translationFiles[getVersionFileName(version.versionName)]!.content;
return { return {
...version, ...version,
versionLabel: label: versionTranslations['version.label']?.message ?? version.label,
versionTranslations['version.label']?.message ?? version.versionLabel,
sidebars: translateSidebars(version, versionTranslations), sidebars: translateSidebars(version, versionTranslations),
// docs: translateDocs(version.docs, versionTranslations), // docs: translateDocs(version.docs, versionTranslations),
}; };

View file

@ -8,13 +8,13 @@
/// <reference types="@docusaurus/module-type-aliases" /> /// <reference types="@docusaurus/module-type-aliases" />
import type {Sidebars} from './sidebars/types'; import type {Sidebars} from './sidebars/types';
import type {BrokenMarkdownLink, Tag} from '@docusaurus/utils';
import type { import type {
Tag, VersionMetadata,
FrontMatterTag, LastUpdateData,
BrokenMarkdownLink, DocMetadata,
ContentPaths, CategoryGeneratedIndexMetadata,
} from '@docusaurus/utils'; } from '@docusaurus/plugin-content-docs';
import type {VersionBanner} from '@docusaurus/plugin-content-docs';
export type DocFile = { export type DocFile = {
contentPath: string; // /!\ may be localized contentPath: string; // /!\ may be localized
@ -24,106 +24,19 @@ export type DocFile = {
lastUpdate: LastUpdateData; lastUpdate: LastUpdateData;
}; };
export type VersionMetadata = ContentPaths & {
versionName: string; // 1.0.0
versionLabel: string; // Version 1.0.0
versionPath: string; // /baseUrl/docs/1.0.0
tagsPath: string;
versionEditUrl?: string | undefined;
versionEditUrlLocalized?: string | undefined;
versionBanner: VersionBanner | null;
versionBadge: boolean;
versionClassName: string;
isLast: boolean;
sidebarFilePath: string | false | undefined; // versioned_sidebars/1.0.0.json
routePriority: number | undefined; // -1 for the latest docs
};
export type LastUpdateData = {
lastUpdatedAt?: number;
formattedLastUpdatedAt?: string;
lastUpdatedBy?: string;
};
export type DocFrontMatter = {
// Front matter uses snake case
id?: string;
title?: string;
tags?: FrontMatterTag[];
hide_title?: boolean;
hide_table_of_contents?: boolean;
keywords?: string[];
image?: string;
description?: string;
slug?: string;
sidebar_label?: string;
sidebar_position?: number;
sidebar_class_name?: string;
sidebar_custom_props?: {[key: string]: unknown};
displayed_sidebar?: string | null;
pagination_label?: string;
custom_edit_url?: string | null;
parse_number_prefixes?: boolean;
toc_min_heading_level?: number;
toc_max_heading_level?: number;
pagination_next?: string | null;
pagination_prev?: string | null;
};
export type DocMetadataBase = LastUpdateData & {
id: string; // TODO legacy versioned id => try to remove
unversionedId: string; // TODO new unversioned id => try to rename to "id"
version: string;
title: string;
description: string;
source: string; // @site aliased posix source => "@site/docs/folder/subFolder/subSubFolder/myDoc.md"
sourceDirName: string; // posix path relative to the versioned docs folder (can be ".") => "folder/subFolder/subSubFolder"
slug: string;
permalink: string;
sidebarPosition?: number;
editUrl?: string | null;
tags: Tag[];
frontMatter: DocFrontMatter & {[key: string]: unknown};
};
export type DocNavLink = {
title: string;
permalink: string;
};
export type DocMetadata = DocMetadataBase & {
sidebar?: string;
previous?: DocNavLink;
next?: DocNavLink;
};
export type CategoryGeneratedIndexMetadata = {
title: string;
description?: string;
slug: string;
permalink: string;
sidebar: string;
previous?: DocNavLink;
next?: DocNavLink;
image?: string;
keywords?: string | readonly string[];
};
export type SourceToPermalink = { export type SourceToPermalink = {
[source: string]: string; [source: string]: string;
}; };
export type VersionTag = { export type VersionTag = Tag & {
name: string; // normalized name/label of the tag /** all doc ids having this tag. */
docIds: string[]; // all doc ids having this tag docIds: string[];
permalink: string; // pathname of the tag
}; };
export type VersionTags = { export type VersionTags = {
[key: string]: VersionTag; [key: string]: VersionTag;
}; };
export type LoadedVersion = VersionMetadata & { export type LoadedVersion = VersionMetadata & {
versionPath: string;
mainDocId: string; mainDocId: string;
docs: DocMetadata[]; docs: DocMetadata[];
sidebars: Sidebars; sidebars: Sidebars;

View file

@ -7,7 +7,6 @@
import path from 'path'; import path from 'path';
import fs from 'fs-extra'; import fs from 'fs-extra';
import type {VersionMetadata} from './types';
import { import {
VERSIONS_JSON_FILE, VERSIONS_JSON_FILE,
VERSIONED_DOCS_DIR, VERSIONED_DOCS_DIR,
@ -17,8 +16,8 @@ import {
import type { import type {
PluginOptions, PluginOptions,
VersionBanner, VersionBanner,
VersionOptions,
VersionsOptions, VersionsOptions,
VersionMetadata,
} from '@docusaurus/plugin-content-docs'; } from '@docusaurus/plugin-content-docs';
import type {LoadContext} from '@docusaurus/types'; import type {LoadContext} from '@docusaurus/types';
@ -207,7 +206,12 @@ function getVersionEditUrls({
contentPath, contentPath,
contentPathLocalized, contentPathLocalized,
context: {siteDir, i18n}, context: {siteDir, i18n},
options: {id, path: currentVersionPath, editUrl, editCurrentVersion}, options: {
id,
path: currentVersionPath,
editUrl: editUrlOption,
editCurrentVersion,
},
}: { }: {
contentPath: string; contentPath: string;
contentPathLocalized: string; contentPathLocalized: string;
@ -216,15 +220,11 @@ function getVersionEditUrls({
PluginOptions, PluginOptions,
'id' | 'path' | 'editUrl' | 'editCurrentVersion' 'id' | 'path' | 'editUrl' | 'editCurrentVersion'
>; >;
}): {versionEditUrl: string; versionEditUrlLocalized: string} | undefined { }): Pick<VersionMetadata, 'editUrl' | 'editUrlLocalized'> {
if (!editUrl) { // If the user is using the functional form of editUrl,
return undefined; // she has total freedom and we can't compute a "version edit url"
} if (!editUrlOption || typeof editUrlOption === 'function') {
return {editUrl: undefined, editUrlLocalized: undefined};
// if the user is using the functional form of editUrl,
// he has total freedom and we can't compute a "version edit url"
if (typeof editUrl === 'function') {
return undefined;
} }
const editDirPath = editCurrentVersion ? currentVersionPath : contentPath; const editDirPath = editCurrentVersion ? currentVersionPath : contentPath;
@ -244,16 +244,16 @@ function getVersionEditUrls({
path.relative(siteDir, path.resolve(siteDir, editDirPathLocalized)), path.relative(siteDir, path.resolve(siteDir, editDirPathLocalized)),
); );
const versionEditUrl = normalizeUrl([editUrl, versionPathSegment]); const editUrl = normalizeUrl([editUrlOption, versionPathSegment]);
const versionEditUrlLocalized = normalizeUrl([ const editUrlLocalized = normalizeUrl([
editUrl, editUrlOption,
versionPathSegmentLocalized, versionPathSegmentLocalized,
]); ]);
return { return {
versionEditUrl, editUrl,
versionEditUrlLocalized, editUrlLocalized,
}; };
} }
@ -370,12 +370,12 @@ function createVersionMetadata({
} }
const defaultVersionPathPart = getDefaultVersionPathPart(); const defaultVersionPathPart = getDefaultVersionPathPart();
const versionOptions: VersionOptions = options.versions[versionName] ?? {}; const versionOptions = options.versions[versionName] ?? {};
const versionLabel = versionOptions.label ?? defaultVersionLabel; const label = versionOptions.label ?? defaultVersionLabel;
const versionPathPart = versionOptions.path ?? defaultVersionPathPart; const versionPathPart = versionOptions.path ?? defaultVersionPathPart;
const versionPath = normalizeUrl([ const routePath = normalizeUrl([
context.baseUrl, context.baseUrl,
options.routeBasePath, options.routeBasePath,
versionPathPart, versionPathPart,
@ -388,28 +388,27 @@ function createVersionMetadata({
options, options,
}); });
// Because /docs/:route` should always be after `/docs/versionName/:route`.
const routePriority = versionPathPart === '' ? -1 : undefined; const routePriority = versionPathPart === '' ? -1 : undefined;
// the path that will be used to refer the docs tags // the path that will be used to refer the docs tags
// example below will be using /docs/tags // example below will be using /docs/tags
const tagsPath = normalizeUrl([versionPath, options.tagsBasePath]); const tagsPath = normalizeUrl([routePath, options.tagsBasePath]);
return { return {
versionName, versionName,
versionLabel, label,
versionPath, path: routePath,
tagsPath, tagsPath,
versionEditUrl: versionEditUrls?.versionEditUrl, editUrl: versionEditUrls.editUrl,
versionEditUrlLocalized: versionEditUrls?.versionEditUrlLocalized, editUrlLocalized: versionEditUrls.editUrlLocalized,
versionBanner: getVersionBanner({ banner: getVersionBanner({
versionName, versionName,
versionNames, versionNames,
lastVersionName, lastVersionName,
options, options,
}), }),
versionBadge: getVersionBadge({versionName, versionNames, options}), badge: getVersionBadge({versionName, versionNames, options}),
versionClassName: getVersionClassName({versionName, options}), className: getVersionClassName({versionName, options}),
isLast, isLast,
routePriority, routePriority,
sidebarFilePath, sidebarFilePath,
@ -592,15 +591,3 @@ export async function readVersionsMetadata({
); );
return versionsMetadata; return versionsMetadata;
} }
// order matter!
// Read in priority the localized path, then the unlocalized one
// We want the localized doc to "override" the unlocalized one
export function getDocsDirPaths(
versionMetadata: Pick<
VersionMetadata,
'contentPath' | 'contentPathLocalized'
>,
): [string, string] {
return [versionMetadata.contentPathLocalized, versionMetadata.contentPath];
}

View file

@ -6,9 +6,9 @@
*/ */
declare module '@docusaurus/plugin-content-pages' { declare module '@docusaurus/plugin-content-pages' {
import type {RemarkAndRehypePluginOptions} from '@docusaurus/mdx-loader'; import type {MDXOptions} from '@docusaurus/mdx-loader';
export type PluginOptions = RemarkAndRehypePluginOptions & { export type PluginOptions = MDXOptions & {
id?: string; id?: string;
path: string; path: string;
routeBasePath: string; routeBasePath: string;

View file

@ -5,6 +5,13 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
/* eslint-disable @typescript-eslint/triple-slash-reference */
/// <reference types="@docusaurus/module-type-aliases" />
/// <reference types="@docusaurus/plugin-content-docs" />
/// <reference types="@docusaurus/plugin-content-blog" />
/// <reference types="@docusaurus/plugin-content-pages" />
declare module '@docusaurus/theme-classic' { declare module '@docusaurus/theme-classic' {
export type Options = { export type Options = {
customCss?: string | string[]; customCss?: string | string[];

View file

@ -47,7 +47,7 @@ function DocItemContent(props: Props): JSX.Element {
const {title} = metadata; const {title} = metadata;
// We only add a title if: // We only add a title if:
// - user asks to hide it with front matter // - user doesn't ask to hide it with front matter
// - the markdown content does not already contain a top-level h1 heading // - the markdown content does not already contain a top-level h1 heading
const shouldAddTitle = const shouldAddTitle =
!hideTitle && typeof DocContent.contentTitle === 'undefined'; !hideTitle && typeof DocContent.contentTitle === 'undefined';

View file

@ -1,11 +0,0 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/// <reference types="@docusaurus/module-type-aliases" />
/// <reference types="@docusaurus/plugin-content-blog" />
/// <reference types="@docusaurus/plugin-content-docs" />
/// <reference types="@docusaurus/plugin-content-pages" />

View file

@ -6,6 +6,7 @@
*/ */
/// <reference types="@docusaurus/theme-classic" /> /// <reference types="@docusaurus/theme-classic" />
/// <reference types="@docusaurus/module-type-aliases" />
declare module '@theme-init/CodeBlock' { declare module '@theme-init/CodeBlock' {
import type CodeBlock, {Props as BaseProps} from '@theme/CodeBlock'; import type CodeBlock, {Props as BaseProps} from '@theme/CodeBlock';

View file

@ -31,24 +31,23 @@ Accepted fields:
| Name | Type | Default | Description | | Name | Type | Default | Description |
| --- | --- | --- | --- | | --- | --- | --- | --- |
| `path` | `string` | `'docs'` | Path to data on filesystem relative to site dir. | | `path` | `string` | `'docs'` | Path to the docs content directory on the file system, relative to site directory. |
| `breadcrumbs` | `boolean` | `true` | To enable or disable the breadcrumbs on docs pages. |
| `editUrl` | <code>string \| EditUrlFunction</code> | `undefined` | Base URL to edit your site. The final URL is computed by `editUrl + relativeDocPath`. Using a function allows more nuanced control for each file. Omitting this variable entirely will disable edit links. | | `editUrl` | <code>string \| EditUrlFunction</code> | `undefined` | Base URL to edit your site. The final URL is computed by `editUrl + relativeDocPath`. Using a function allows more nuanced control for each file. Omitting this variable entirely will disable edit links. |
| `editLocalizedFiles` | `boolean` | `false` | The edit URL will target the localized file, instead of the original unlocalized file. Ignored when `editUrl` is a function. | | `editLocalizedFiles` | `boolean` | `false` | The edit URL will target the localized file, instead of the original unlocalized file. Ignored when `editUrl` is a function. |
| `editCurrentVersion` | `boolean` | `false` | The edit URL will always target the current version doc instead of older versions. Ignored when `editUrl` is a function. | | `editCurrentVersion` | `boolean` | `false` | The edit URL will always target the current version doc instead of older versions. Ignored when `editUrl` is a function. |
| `routeBasePath` | `string` | `'docs'` | URL route for the docs section of your site. **DO NOT** include a trailing slash. Use `/` for shipping docs without base path. | | `routeBasePath` | `string` | `'docs'` | URL route for the docs section of your site. **DO NOT** include a trailing slash. Use `/` for shipping docs without base path. |
| `tagsBasePath` | `string` | `'tags'` | URL route for the tags list page of your site. It is prepended to the `routeBasePath`. | | `tagsBasePath` | `string` | `'tags'` | URL route for the tags list page of your site. It is prepended to the `routeBasePath`. |
| `include` | `string[]` | `['**/*.{md,mdx}']` | Matching files will be included and processed. | | `include` | `string[]` | `['**/*.{md,mdx}']` | Array of glob patterns matching Markdown files to be built, relative to the content path. |
| `exclude` | `string[]` | _See example configuration_ | No route will be created for matching files. | | `exclude` | `string[]` | _See example configuration_ | Array of glob patterns matching Markdown files to be excluded. Serves as refinement based on the `include` option. |
| `sidebarPath` | <code>false \| string</code> | `undefined` (creates autogenerated sidebar) | Path to sidebar configuration. | | `sidebarPath` | <code>false \| string</code> | `undefined` | Path to sidebar configuration. Use `false` to disable sidebars, or `undefined` to create a fully autogenerated sidebar. |
| `sidebarCollapsible` | `boolean` | `true` | Whether sidebar categories are collapsible by default. See also [Collapsible categories](/docs/sidebar#collapsible-categories) | | `sidebarCollapsible` | `boolean` | `true` | Whether sidebar categories are collapsible by default. See also [Collapsible categories](/docs/sidebar#collapsible-categories) |
| `sidebarCollapsed` | `boolean` | `true` | Whether sidebar categories are collapsed by default. See also [Expanded categories by default](/docs/sidebar#expanded-categories-by-default) | | `sidebarCollapsed` | `boolean` | `true` | Whether sidebar categories are collapsed by default. See also [Expanded categories by default](/docs/sidebar#expanded-categories-by-default) |
| `sidebarItemsGenerator` | `SidebarGenerator` | _Omitted_ | Function used to replace the sidebar items of type `'autogenerated'` by real sidebar items (docs, categories, links...). See also [Customize the sidebar items generator](/docs/sidebar#customize-the-sidebar-items-generator) | | `sidebarItemsGenerator` | `SidebarGenerator` | _Omitted_ | Function used to replace the sidebar items of type `'autogenerated'` with real sidebar items (docs, categories, links...). See also [Customize the sidebar items generator](/docs/sidebar#customize-the-sidebar-items-generator) |
| `numberPrefixParser` | <code>boolean \| PrefixParser</code> | _Omitted_ | Custom parsing logic to extract number prefixes from file names. Use `false` to disable this behavior and leave the docs untouched, and `true` to use the default parser. See also [Using number prefixes](/docs/sidebar#using-number-prefixes) | | `numberPrefixParser` | <code>boolean \| PrefixParser</code> | _Omitted_ | Custom parsing logic to extract number prefixes from file names. Use `false` to disable this behavior and leave the docs untouched, and `true` to use the default parser. See also [Using number prefixes](/docs/sidebar#using-number-prefixes) |
| `docLayoutComponent` | `string` | `'@theme/DocPage'` | Root Layout component of each doc page. | | `docLayoutComponent` | `string` | `'@theme/DocPage'` | Root layout component of each doc page. Provides the version data context, and is not unmounted when switching docs. |
| `docItemComponent` | `string` | `'@theme/DocItem'` | Main doc container, with TOC, pagination, etc. | | `docItemComponent` | `string` | `'@theme/DocItem'` | Main doc container, with TOC, pagination, etc. |
| `docTagsListComponent` | `string` | `'@theme/DocTagsListPage'` | Root component of the tags list page | | `docTagsListComponent` | `string` | `'@theme/DocTagsListPage'` | Root component of the tags list page |
| `docTagDocListComponent` | `string` | `'@theme/DocTagDocListPage'` | Root component of the "docs containing tag" page. | | `docTagDocListComponent` | `string` | `'@theme/DocTagDocListPage'` | Root component of the "docs containing tag X" page. |
| `docCategoryGeneratedIndexComponent` | `string` | `'@theme/DocCategoryGeneratedIndexPage'` | Root component of the generated category index page. | | `docCategoryGeneratedIndexComponent` | `string` | `'@theme/DocCategoryGeneratedIndexPage'` | Root component of the generated category index page. |
| `remarkPlugins` | `any[]` | `[]` | Remark plugins passed to MDX. | | `remarkPlugins` | `any[]` | `[]` | Remark plugins passed to MDX. |
| `rehypePlugins` | `any[]` | `[]` | Rehype plugins passed to MDX. | | `rehypePlugins` | `any[]` | `[]` | Rehype plugins passed to MDX. |
@ -56,11 +55,12 @@ Accepted fields:
| `beforeDefaultRehypePlugins` | `any[]` | `[]` | Custom Rehype plugins passed to MDX before the default Docusaurus Rehype plugins. | | `beforeDefaultRehypePlugins` | `any[]` | `[]` | Custom Rehype plugins passed to MDX before the default Docusaurus Rehype plugins. |
| `showLastUpdateAuthor` | `boolean` | `false` | Whether to display the author who last updated the doc. | | `showLastUpdateAuthor` | `boolean` | `false` | Whether to display the author who last updated the doc. |
| `showLastUpdateTime` | `boolean` | `false` | Whether to display the last date the doc was updated. | | `showLastUpdateTime` | `boolean` | `false` | Whether to display the last date the doc was updated. |
| `disableVersioning` | `boolean` | `false` | Explicitly disable versioning even with versions. This will make the site only include the current version. | | `breadcrumbs` | `boolean` | `true` | Enable or disable the breadcrumbs on doc pages. |
| `disableVersioning` | `boolean` | `false` | Explicitly disable versioning even when multiple versions exist. This will make the site only include the current version. Will error if `includeCurrentVersion: false` and `disableVersioning: true`. |
| `includeCurrentVersion` | `boolean` | `true` | Include the current version of your docs. | | `includeCurrentVersion` | `boolean` | `true` | Include the current version of your docs. |
| `lastVersion` | `string` | First version in `versions.json` | Set the version navigated to in priority and displayed by default for docs navbar items. | | `lastVersion` | `string` | First version in `versions.json` | The version navigated to in priority and displayed by default for docs navbar items. |
| `onlyIncludeVersions` | `string[]` | All versions available | Only include a subset of all available versions. | | `onlyIncludeVersions` | `string[]` | All versions available | Only include a subset of all available versions. |
| `versions` | `Versions` | `{}` | Independent customization of each version's properties. | | `versions` | `VersionsConfig` | `{}` | Independent customization of each version's properties. |
</APITable> </APITable>
@ -78,15 +78,24 @@ type PrefixParser = (filename: string) => {
numberPrefix?: number; numberPrefix?: number;
}; };
type CategoryIndexMatcher = (doc: { type CategoryIndexMatcher = (param: {
/** The file name, without extension */
fileName: string; fileName: string;
/**
* The list of directories, from lowest level to highest.
* If there's no dir name, directories is ['.']
*/
directories: string[]; directories: string[];
/** The extension, with a leading dot */
extension: string; extension: string;
}) => boolean; }) => boolean;
type SidebarGenerator = (generatorArgs: { type SidebarGenerator = (generatorArgs: {
item: {type: 'autogenerated'; dirName: string}; // the sidebar item with type "autogenerated" /** The sidebar item with type "autogenerated" to be transformed. */
version: {contentPath: string; versionName: string}; // the current version item: {type: 'autogenerated'; dirName: string};
/** Useful metadata for the version this sidebar belongs to. */
version: {contentPath: string; versionName: string};
/** All the docs of that version (unfiltered). */
docs: Array<{ docs: Array<{
id: string; id: string;
title: string; title: string;
@ -94,23 +103,40 @@ type SidebarGenerator = (generatorArgs: {
source: string; source: string;
sourceDirName: string; sourceDirName: string;
sidebarPosition?: number | undefined; sidebarPosition?: number | undefined;
}>; // all the docs of that version (unfiltered) }>;
numberPrefixParser: PrefixParser; // numberPrefixParser configured for this plugin /** Number prefix parser configured for this plugin. */
categoriesMetadata: Record<string, CategoryMetadata>; // key is the path relative to the doc directory, value is the category metadata file's content numberPrefixParser: PrefixParser;
isCategoryIndex: CategoryIndexMatcher; // the default category index matcher, that you can override /** The default category index matcher which you can override. */
defaultSidebarItemsGenerator: SidebarGenerator; // useful to re-use/enhance default sidebar generation logic from Docusaurus isCategoryIndex: CategoryIndexMatcher;
/**
* key is the path relative to the doc content directory, value is the
* category metadata file's content.
*/
categoriesMetadata: {[filePath: string]: CategoryMetadata};
/**
* Useful to re-use/enhance the default sidebar generation logic from
* Docusaurus.
*/
defaultSidebarItemsGenerator: SidebarGenerator;
}) => Promise<SidebarItem[]>; }) => Promise<SidebarItem[]>;
type Versions = Record< type VersionsConfig = {
string, // the version's ID [versionName: string]: {
{ /**
label: string; // the label of the version * The base path of the version, will be appended to `baseUrl` +
path: string; // the route path of the version * `routeBasePath`.
banner: 'none' | 'unreleased' | 'unmaintained'; // the banner to show at the top of a doc of that version */
badge: boolean; // show a badge with the version name at the top of a doc of that version path?: string;
className; // add a custom className to the <html> element when browsing docs of that version /** The label of the version to be used in badges, dropdowns, etc. */
} label?: string;
>; /** The banner to show at the top of a doc of that version. */
banner?: 'none' | 'unreleased' | 'unmaintained';
/** Show a badge with the version label at the top of each doc. */
badge?: boolean;
/** Add a custom class name to the <html> element of each doc */
className?: string;
};
};
``` ```
### Example configuration {#ex-config} ### Example configuration {#ex-config}