feat(v2): auto-generated sidebars, frontmatter-less sites (#4582)

* POC of autogenerated sidebars

* use combine-promises utility lib

* autogenerated sidebar poc working

* Revert "autogenerated sidebar poc working"

This reverts commit c81da980

* POC of auto-generated sidebars for community docs

* update tests

* add initial test suite for autogenerated sidebars + fix some edge cases

* Improve autogen sidebars: strip more number prefixes in folder breadcrumb + slugs

* fix typo!

* Add tests for partially generated sidebars + fix edge cases + extract sidebar generation code

* Ability to read category metadatas file from a file in the category

* fix tests

* change position of API

* ability to extract number prefix

* stable system to enable position frontmatter

* fix tests for autogen sidebar position

* renamings

* restore community sidebars

* rename frontmatter position -> sidebar_position

* make sidebarItemsGenerator fn configurable

* minor changes

* rename dirPath => dirName

* Make the init template use autogenerated sidebars

* fix options

* fix docusaurus site: remove test docs

* add _category_ file to docs pathsToWatch

* add _category_ file to docs pathsToWatch

* tutorial: use sidebar_position instead of file number prefixes

* Adapt Docusaurus tutorial for autogenerated sidebars

* remove slug: /

* polish the homepage template

* rename _category_ sidebar_position to just "position"

* test for custom sidebarItemsGenerator fn

* fix category metadata + add link to report tutorial issues

* fix absolute path breaking tests

* fix absolute path breaking tests

* Add test for floating number sidebar_position

* add sidebarItemsGenerator unit tests

* add processSidebars unit tests

* Fix init template broken links

* windows test

* increase code translations test timeout

* cleanup mockCategoryMetadataFiles after windows test fixed

* update init template positions

* fix windows tests

* fix comment

* Add autogenerated sidebar items documentation + rewrite the full sidebars page doc

* add useful comment

* fix code block title
This commit is contained in:
Sébastien Lorber 2021-04-15 16:20:11 +02:00 committed by GitHub
parent 836f92708a
commit db79d462ab
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
67 changed files with 2887 additions and 306 deletions

View file

@ -10,7 +10,7 @@
import path from 'path';
import {isMatch} from 'picomatch';
import commander from 'commander';
import {kebabCase} from 'lodash';
import {kebabCase, orderBy} from 'lodash';
import fs from 'fs-extra';
import pluginContentDocs from '../index';
@ -24,7 +24,7 @@ import {DEFAULT_PLUGIN_ID} from '@docusaurus/core/lib/constants';
import * as cliDocs from '../cli';
import {OptionsSchema} from '../options';
import {normalizePluginOptions} from '@docusaurus/utils-validation';
import {DocMetadata, LoadedVersion} from '../types';
import {DocMetadata, LoadedVersion, SidebarItemsGenerator} from '../types';
import {toSidebarsProp} from '../props';
// @ts-expect-error: TODO typedefs missing?
@ -33,6 +33,17 @@ import {validate} from 'webpack';
function findDocById(version: LoadedVersion, unversionedId: string) {
return version.docs.find((item) => item.unversionedId === unversionedId);
}
function getDocById(version: LoadedVersion, unversionedId: string) {
const doc = findDocById(version, unversionedId);
if (!doc) {
throw new Error(
`No doc found with id=${unversionedId} in version ${version.versionName}.
Available ids=\n- ${version.docs.map((d) => d.unversionedId).join('\n- ')}`,
);
}
return doc;
}
const defaultDocMetadata: Partial<DocMetadata> = {
next: undefined,
previous: undefined,
@ -40,6 +51,7 @@ const defaultDocMetadata: Partial<DocMetadata> = {
lastUpdatedAt: undefined,
lastUpdatedBy: undefined,
sidebar_label: undefined,
formattedLastUpdatedAt: undefined,
};
const createFakeActions = (contentDir: string) => {
@ -203,6 +215,7 @@ describe('simple website', () => {
"sidebars.json",
"i18n/en/docusaurus-plugin-content-docs/current/**/*.{md,mdx}",
"docs/**/*.{md,mdx}",
"docs/**/_category_.{json,yml,yaml}",
]
`);
expect(isMatch('docs/hello.md', matchPattern)).toEqual(true);
@ -247,6 +260,7 @@ describe('simple website', () => {
version: 'current',
id: 'hello',
unversionedId: 'hello',
sourceDirName: '.',
isDocsHomePage: true,
permalink: '/docs/',
slug: '/',
@ -268,11 +282,12 @@ describe('simple website', () => {
},
});
expect(findDocById(currentVersion, 'foo/bar')).toEqual({
expect(getDocById(currentVersion, 'foo/bar')).toEqual({
...defaultDocMetadata,
version: 'current',
id: 'foo/bar',
unversionedId: 'foo/bar',
sourceDirName: 'foo',
isDocsHomePage: false,
next: {
title: 'baz',
@ -368,15 +383,19 @@ describe('versioned website', () => {
"sidebars.json",
"i18n/en/docusaurus-plugin-content-docs/current/**/*.{md,mdx}",
"docs/**/*.{md,mdx}",
"docs/**/_category_.{json,yml,yaml}",
"versioned_sidebars/version-1.0.1-sidebars.json",
"i18n/en/docusaurus-plugin-content-docs/version-1.0.1/**/*.{md,mdx}",
"versioned_docs/version-1.0.1/**/*.{md,mdx}",
"versioned_docs/version-1.0.1/**/_category_.{json,yml,yaml}",
"versioned_sidebars/version-1.0.0-sidebars.json",
"i18n/en/docusaurus-plugin-content-docs/version-1.0.0/**/*.{md,mdx}",
"versioned_docs/version-1.0.0/**/*.{md,mdx}",
"versioned_docs/version-1.0.0/**/_category_.{json,yml,yaml}",
"versioned_sidebars/version-withSlugs-sidebars.json",
"i18n/en/docusaurus-plugin-content-docs/version-withSlugs/**/*.{md,mdx}",
"versioned_docs/version-withSlugs/**/*.{md,mdx}",
"versioned_docs/version-withSlugs/**/_category_.{json,yml,yaml}",
]
`);
expect(isMatch('docs/hello.md', matchPattern)).toEqual(true);
@ -427,10 +446,11 @@ describe('versioned website', () => {
expect(findDocById(version101, 'foo/baz')).toBeUndefined();
expect(findDocById(versionWithSlugs, 'foo/baz')).toBeUndefined();
expect(findDocById(currentVersion, 'foo/bar')).toEqual({
expect(getDocById(currentVersion, 'foo/bar')).toEqual({
...defaultDocMetadata,
id: 'foo/bar',
unversionedId: 'foo/bar',
sourceDirName: 'foo',
isDocsHomePage: false,
permalink: '/docs/next/foo/barSlug',
slug: '/foo/barSlug',
@ -452,10 +472,11 @@ describe('versioned website', () => {
permalink: '/docs/next/',
},
});
expect(findDocById(currentVersion, 'hello')).toEqual({
expect(getDocById(currentVersion, 'hello')).toEqual({
...defaultDocMetadata,
id: 'hello',
unversionedId: 'hello',
sourceDirName: '.',
isDocsHomePage: true,
permalink: '/docs/next/',
slug: '/',
@ -474,10 +495,11 @@ describe('versioned website', () => {
permalink: '/docs/next/foo/barSlug',
},
});
expect(findDocById(version101, 'hello')).toEqual({
expect(getDocById(version101, 'hello')).toEqual({
...defaultDocMetadata,
id: 'version-1.0.1/hello',
unversionedId: 'hello',
sourceDirName: '.',
isDocsHomePage: true,
permalink: '/docs/',
slug: '/',
@ -496,10 +518,11 @@ describe('versioned website', () => {
permalink: '/docs/foo/bar',
},
});
expect(findDocById(version100, 'foo/baz')).toEqual({
expect(getDocById(version100, 'foo/baz')).toEqual({
...defaultDocMetadata,
id: 'version-1.0.0/foo/baz',
unversionedId: 'foo/baz',
sourceDirName: 'foo',
isDocsHomePage: false,
permalink: '/docs/1.0.0/foo/baz',
slug: '/foo/baz',
@ -611,9 +634,11 @@ describe('versioned website (community)', () => {
"community_sidebars.json",
"i18n/en/docusaurus-plugin-content-docs-community/current/**/*.{md,mdx}",
"community/**/*.{md,mdx}",
"community/**/_category_.{json,yml,yaml}",
"community_versioned_sidebars/version-1.0.0-sidebars.json",
"i18n/en/docusaurus-plugin-content-docs-community/version-1.0.0/**/*.{md,mdx}",
"community_versioned_docs/version-1.0.0/**/*.{md,mdx}",
"community_versioned_docs/version-1.0.0/**/_category_.{json,yml,yaml}",
]
`);
expect(isMatch('community/team.md', matchPattern)).toEqual(true);
@ -644,10 +669,11 @@ describe('versioned website (community)', () => {
expect(content.loadedVersions.length).toEqual(2);
const [currentVersion, version100] = content.loadedVersions;
expect(findDocById(currentVersion, 'team')).toEqual({
expect(getDocById(currentVersion, 'team')).toEqual({
...defaultDocMetadata,
id: 'team',
unversionedId: 'team',
sourceDirName: '.',
isDocsHomePage: false,
permalink: '/community/next/team',
slug: '/team',
@ -659,10 +685,11 @@ describe('versioned website (community)', () => {
sidebar: 'community',
frontMatter: {title: 'Team title translated'},
});
expect(findDocById(version100, 'team')).toEqual({
expect(getDocById(version100, 'team')).toEqual({
...defaultDocMetadata,
id: 'version-1.0.0/team',
unversionedId: 'team',
sourceDirName: '.',
isDocsHomePage: false,
permalink: '/community/team',
slug: '/team',
@ -709,7 +736,7 @@ describe('site with doc label', () => {
}),
);
const content = await plugin.loadContent();
const content = (await plugin.loadContent?.())!;
return {content};
}
@ -730,3 +757,807 @@ describe('site with doc label', () => {
expect(sidebarProps.docs[1].label).toBe('Hello 2 From Doc');
});
});
describe('site with full autogenerated sidebar', () => {
async function loadSite() {
const siteDir = path.join(
__dirname,
'__fixtures__',
'site-with-autogenerated-sidebar',
);
const context = await loadContext(siteDir);
const plugin = pluginContentDocs(
context,
normalizePluginOptions(OptionsSchema, {
path: 'docs',
}),
);
const content = (await plugin.loadContent?.())!;
return {content, siteDir};
}
test('sidebar is fully autogenerated', async () => {
const {content} = await loadSite();
const version = content.loadedVersions[0];
expect(version.sidebars).toEqual({
defaultSidebar: [
{
type: 'doc',
id: 'getting-started',
},
{
type: 'doc',
id: 'installation',
},
{
type: 'category',
label: 'Guides',
collapsed: true,
items: [
{
type: 'doc',
id: 'Guides/guide1',
},
{
type: 'doc',
id: 'Guides/guide2',
},
{
type: 'doc',
id: 'Guides/guide2.5',
},
{
type: 'doc',
id: 'Guides/guide3',
},
{
type: 'doc',
id: 'Guides/guide4',
},
{
type: 'doc',
id: 'Guides/guide5',
},
],
},
{
type: 'category',
label: 'API (label from _category_.json)',
collapsed: true,
items: [
{
type: 'doc',
id: 'API/api-overview',
},
{
type: 'category',
label: 'Core APIs',
collapsed: true,
items: [
{
type: 'doc',
id: 'API/Core APIs/Client API',
},
{
type: 'doc',
id: 'API/Core APIs/Server API',
},
],
},
{
type: 'category',
label: 'Extension APIs (label from _category_.yml)',
collapsed: true,
items: [
{
type: 'doc',
id: 'API/Extension APIs/Plugin API',
},
{
type: 'doc',
id: 'API/Extension APIs/Theme API',
},
],
},
{
type: 'doc',
id: 'API/api-end',
},
],
},
],
});
});
test('docs in fully generated sidebar have correct metadatas', async () => {
const {content, siteDir} = await loadSite();
const version = content.loadedVersions[0];
expect(getDocById(version, 'getting-started')).toEqual({
...defaultDocMetadata,
id: 'getting-started',
unversionedId: 'getting-started',
sourceDirName: '.',
isDocsHomePage: false,
permalink: '/docs/getting-started',
slug: '/getting-started',
source: path.posix.join(
'@site',
posixPath(path.relative(siteDir, version.contentPath)),
'0-getting-started.md',
),
title: 'Getting Started',
description: 'Getting started text',
version: 'current',
sidebar: 'defaultSidebar',
frontMatter: {},
sidebarPosition: 0,
previous: undefined,
next: {
permalink: '/docs/installation',
title: 'Installation',
},
});
expect(getDocById(version, 'installation')).toEqual({
...defaultDocMetadata,
id: 'installation',
unversionedId: 'installation',
sourceDirName: '.',
isDocsHomePage: false,
permalink: '/docs/installation',
slug: '/installation',
source: path.posix.join(
'@site',
posixPath(path.relative(siteDir, version.contentPath)),
'1-installation.md',
),
title: 'Installation',
description: 'Installation text',
version: 'current',
sidebar: 'defaultSidebar',
frontMatter: {},
sidebarPosition: 1,
previous: {
permalink: '/docs/getting-started',
title: 'Getting Started',
},
next: {
permalink: '/docs/Guides/guide1',
title: 'Guide 1',
},
});
expect(getDocById(version, 'Guides/guide1')).toEqual({
...defaultDocMetadata,
id: 'Guides/guide1',
unversionedId: 'Guides/guide1',
sourceDirName: 'Guides',
isDocsHomePage: false,
permalink: '/docs/Guides/guide1',
slug: '/Guides/guide1',
source: path.posix.join(
'@site',
posixPath(path.relative(siteDir, version.contentPath)),
'Guides',
'z-guide1.md',
),
title: 'Guide 1',
description: 'Guide 1 text',
version: 'current',
sidebar: 'defaultSidebar',
frontMatter: {
id: 'guide1',
sidebar_position: 1,
},
sidebarPosition: 1,
previous: {
permalink: '/docs/installation',
title: 'Installation',
},
next: {
permalink: '/docs/Guides/guide2',
title: 'Guide 2',
},
});
expect(getDocById(version, 'Guides/guide2')).toEqual({
...defaultDocMetadata,
id: 'Guides/guide2',
unversionedId: 'Guides/guide2',
sourceDirName: 'Guides',
isDocsHomePage: false,
permalink: '/docs/Guides/guide2',
slug: '/Guides/guide2',
source: path.posix.join(
'@site',
posixPath(path.relative(siteDir, version.contentPath)),
'Guides',
'02-guide2.md',
),
title: 'Guide 2',
description: 'Guide 2 text',
version: 'current',
sidebar: 'defaultSidebar',
frontMatter: {
id: 'guide2',
},
sidebarPosition: 2,
previous: {
permalink: '/docs/Guides/guide1',
title: 'Guide 1',
},
next: {
permalink: '/docs/Guides/guide2.5',
title: 'Guide 2.5',
},
});
expect(getDocById(version, 'Guides/guide2.5')).toEqual({
...defaultDocMetadata,
id: 'Guides/guide2.5',
unversionedId: 'Guides/guide2.5',
sourceDirName: 'Guides',
isDocsHomePage: false,
permalink: '/docs/Guides/guide2.5',
slug: '/Guides/guide2.5',
source: path.posix.join(
'@site',
posixPath(path.relative(siteDir, version.contentPath)),
'Guides',
'0-guide2.5.md',
),
title: 'Guide 2.5',
description: 'Guide 2.5 text',
version: 'current',
sidebar: 'defaultSidebar',
frontMatter: {
id: 'guide2.5',
sidebar_position: 2.5,
},
sidebarPosition: 2.5,
previous: {
permalink: '/docs/Guides/guide2',
title: 'Guide 2',
},
next: {
permalink: '/docs/Guides/guide3',
title: 'Guide 3',
},
});
expect(getDocById(version, 'Guides/guide3')).toEqual({
...defaultDocMetadata,
id: 'Guides/guide3',
unversionedId: 'Guides/guide3',
sourceDirName: 'Guides',
isDocsHomePage: false,
permalink: '/docs/Guides/guide3',
slug: '/Guides/guide3',
source: path.posix.join(
'@site',
posixPath(path.relative(siteDir, version.contentPath)),
'Guides',
'guide3.md',
),
title: 'Guide 3',
description: 'Guide 3 text',
version: 'current',
sidebar: 'defaultSidebar',
frontMatter: {
id: 'guide3',
sidebar_position: 3,
},
sidebarPosition: 3,
previous: {
permalink: '/docs/Guides/guide2.5',
title: 'Guide 2.5',
},
next: {
permalink: '/docs/Guides/guide4',
title: 'Guide 4',
},
});
expect(getDocById(version, 'Guides/guide4')).toEqual({
...defaultDocMetadata,
id: 'Guides/guide4',
unversionedId: 'Guides/guide4',
sourceDirName: 'Guides',
isDocsHomePage: false,
permalink: '/docs/Guides/guide4',
slug: '/Guides/guide4',
source: path.posix.join(
'@site',
posixPath(path.relative(siteDir, version.contentPath)),
'Guides',
'a-guide4.md',
),
title: 'Guide 4',
description: 'Guide 4 text',
version: 'current',
sidebar: 'defaultSidebar',
frontMatter: {
id: 'guide4',
},
sidebarPosition: undefined,
previous: {
permalink: '/docs/Guides/guide3',
title: 'Guide 3',
},
next: {
permalink: '/docs/Guides/guide5',
title: 'Guide 5',
},
});
expect(getDocById(version, 'Guides/guide5')).toEqual({
...defaultDocMetadata,
id: 'Guides/guide5',
unversionedId: 'Guides/guide5',
sourceDirName: 'Guides',
isDocsHomePage: false,
permalink: '/docs/Guides/guide5',
slug: '/Guides/guide5',
source: path.posix.join(
'@site',
posixPath(path.relative(siteDir, version.contentPath)),
'Guides',
'b-guide5.md',
),
title: 'Guide 5',
description: 'Guide 5 text',
version: 'current',
sidebar: 'defaultSidebar',
frontMatter: {
id: 'guide5',
},
sidebarPosition: undefined,
previous: {
permalink: '/docs/Guides/guide4',
title: 'Guide 4',
},
next: {
permalink: '/docs/API/api-overview',
title: 'API Overview',
},
});
expect(getDocById(version, 'API/api-overview')).toEqual({
...defaultDocMetadata,
id: 'API/api-overview',
unversionedId: 'API/api-overview',
sourceDirName: '3-API',
isDocsHomePage: false,
permalink: '/docs/API/api-overview',
slug: '/API/api-overview',
source: path.posix.join(
'@site',
posixPath(path.relative(siteDir, version.contentPath)),
'3-API',
'00_api-overview.md',
),
title: 'API Overview',
description: 'API Overview text',
version: 'current',
sidebar: 'defaultSidebar',
frontMatter: {},
sidebarPosition: 0,
previous: {
permalink: '/docs/Guides/guide5',
title: 'Guide 5',
},
next: {
permalink: '/docs/API/Core APIs/Client API',
title: 'Client API',
},
});
expect(getDocById(version, 'API/Core APIs/Client API')).toEqual({
...defaultDocMetadata,
id: 'API/Core APIs/Client API',
unversionedId: 'API/Core APIs/Client API',
sourceDirName: '3-API/01_Core APIs',
isDocsHomePage: false,
permalink: '/docs/API/Core APIs/Client API',
slug: '/API/Core APIs/Client API',
source: path.posix.join(
'@site',
posixPath(path.relative(siteDir, version.contentPath)),
'3-API',
'01_Core APIs',
'0 --- Client API.md',
),
title: 'Client API',
description: 'Client API text',
version: 'current',
sidebar: 'defaultSidebar',
frontMatter: {},
sidebarPosition: 0,
previous: {
permalink: '/docs/API/api-overview',
title: 'API Overview',
},
next: {
permalink: '/docs/API/Core APIs/Server API',
title: 'Server API',
},
});
expect(getDocById(version, 'API/Core APIs/Server API')).toEqual({
...defaultDocMetadata,
id: 'API/Core APIs/Server API',
unversionedId: 'API/Core APIs/Server API',
sourceDirName: '3-API/01_Core APIs',
isDocsHomePage: false,
permalink: '/docs/API/Core APIs/Server API',
slug: '/API/Core APIs/Server API',
source: path.posix.join(
'@site',
posixPath(path.relative(siteDir, version.contentPath)),
'3-API',
'01_Core APIs',
'1 --- Server API.md',
),
title: 'Server API',
description: 'Server API text',
version: 'current',
sidebar: 'defaultSidebar',
frontMatter: {},
sidebarPosition: 1,
previous: {
permalink: '/docs/API/Core APIs/Client API',
title: 'Client API',
},
next: {
permalink: '/docs/API/Extension APIs/Plugin API',
title: 'Plugin API',
},
});
expect(getDocById(version, 'API/Extension APIs/Plugin API')).toEqual({
...defaultDocMetadata,
id: 'API/Extension APIs/Plugin API',
unversionedId: 'API/Extension APIs/Plugin API',
sourceDirName: '3-API/02_Extension APIs',
isDocsHomePage: false,
permalink: '/docs/API/Extension APIs/Plugin API',
slug: '/API/Extension APIs/Plugin API',
source: path.posix.join(
'@site',
posixPath(path.relative(siteDir, version.contentPath)),
'3-API',
'02_Extension APIs',
'0. Plugin API.md',
),
title: 'Plugin API',
description: 'Plugin API text',
version: 'current',
sidebar: 'defaultSidebar',
frontMatter: {},
sidebarPosition: 0,
previous: {
permalink: '/docs/API/Core APIs/Server API',
title: 'Server API',
},
next: {
permalink: '/docs/API/Extension APIs/Theme API',
title: 'Theme API',
},
});
expect(getDocById(version, 'API/Extension APIs/Theme API')).toEqual({
...defaultDocMetadata,
id: 'API/Extension APIs/Theme API',
unversionedId: 'API/Extension APIs/Theme API',
sourceDirName: '3-API/02_Extension APIs',
isDocsHomePage: false,
permalink: '/docs/API/Extension APIs/Theme API',
slug: '/API/Extension APIs/Theme API',
source: path.posix.join(
'@site',
posixPath(path.relative(siteDir, version.contentPath)),
'3-API',
'02_Extension APIs',
'1. Theme API.md',
),
title: 'Theme API',
description: 'Theme API text',
version: 'current',
sidebar: 'defaultSidebar',
frontMatter: {},
sidebarPosition: 1,
previous: {
permalink: '/docs/API/Extension APIs/Plugin API',
title: 'Plugin API',
},
next: {
permalink: '/docs/API/api-end',
title: 'API End',
},
});
expect(getDocById(version, 'API/api-end')).toEqual({
...defaultDocMetadata,
id: 'API/api-end',
unversionedId: 'API/api-end',
sourceDirName: '3-API',
isDocsHomePage: false,
permalink: '/docs/API/api-end',
slug: '/API/api-end',
source: path.posix.join(
'@site',
posixPath(path.relative(siteDir, version.contentPath)),
'3-API',
'03_api-end.md',
),
title: 'API End',
description: 'API End text',
version: 'current',
sidebar: 'defaultSidebar',
frontMatter: {},
sidebarPosition: 3,
previous: {
permalink: '/docs/API/Extension APIs/Theme API',
title: 'Theme API',
},
next: undefined,
});
});
});
describe('site with partial autogenerated sidebars', () => {
async function loadSite() {
const siteDir = path.join(
__dirname,
'__fixtures__',
'site-with-autogenerated-sidebar',
);
const context = await loadContext(siteDir, {});
const plugin = pluginContentDocs(
context,
normalizePluginOptions(OptionsSchema, {
path: 'docs',
sidebarPath: path.join(
__dirname,
'__fixtures__',
'site-with-autogenerated-sidebar',
'partialAutogeneratedSidebars.js',
),
}),
);
const content = (await plugin.loadContent?.())!;
return {content, siteDir};
}
test('sidebar is partially autogenerated', async () => {
const {content} = await loadSite();
const version = content.loadedVersions[0];
expect(version.sidebars).toEqual({
someSidebar: [
{
type: 'doc',
id: 'API/api-end',
},
{
type: 'category',
label: 'Some category',
collapsed: true,
items: [
{
type: 'doc',
id: 'API/api-overview',
},
{
type: 'doc',
id: 'API/Extension APIs/Plugin API',
},
{
type: 'doc',
id: 'API/Extension APIs/Theme API',
},
],
},
],
});
});
test('docs in partially generated sidebar have correct metadatas', async () => {
const {content, siteDir} = await loadSite();
const version = content.loadedVersions[0];
// Only looking at the docs of the autogen sidebar, others metadatas should not be affected
expect(getDocById(version, 'API/api-end')).toEqual({
...defaultDocMetadata,
id: 'API/api-end',
unversionedId: 'API/api-end',
sourceDirName: '3-API',
isDocsHomePage: false,
permalink: '/docs/API/api-end',
slug: '/API/api-end',
source: path.posix.join(
'@site',
posixPath(path.relative(siteDir, version.contentPath)),
'3-API',
'03_api-end.md',
),
title: 'API End',
description: 'API End text',
version: 'current',
sidebar: 'someSidebar',
frontMatter: {},
sidebarPosition: 3, // ignored (not part of the autogenerated sidebar slice)
previous: undefined,
next: {
permalink: '/docs/API/api-overview',
title: 'API Overview',
},
});
expect(getDocById(version, 'API/api-overview')).toEqual({
...defaultDocMetadata,
id: 'API/api-overview',
unversionedId: 'API/api-overview',
sourceDirName: '3-API',
isDocsHomePage: false,
permalink: '/docs/API/api-overview',
slug: '/API/api-overview',
source: path.posix.join(
'@site',
posixPath(path.relative(siteDir, version.contentPath)),
'3-API',
'00_api-overview.md',
),
title: 'API Overview',
description: 'API Overview text',
version: 'current',
sidebar: 'someSidebar',
frontMatter: {},
sidebarPosition: 0, // ignored (not part of the autogenerated sidebar slice)
previous: {
permalink: '/docs/API/api-end',
title: 'API End',
},
next: {
permalink: '/docs/API/Extension APIs/Plugin API',
title: 'Plugin API',
},
});
expect(getDocById(version, 'API/Extension APIs/Plugin API')).toEqual({
...defaultDocMetadata,
id: 'API/Extension APIs/Plugin API',
unversionedId: 'API/Extension APIs/Plugin API',
sourceDirName: '3-API/02_Extension APIs',
isDocsHomePage: false,
permalink: '/docs/API/Extension APIs/Plugin API',
slug: '/API/Extension APIs/Plugin API',
source: path.posix.join(
'@site',
posixPath(path.relative(siteDir, version.contentPath)),
'3-API',
'02_Extension APIs',
'0. Plugin API.md',
),
title: 'Plugin API',
description: 'Plugin API text',
version: 'current',
sidebar: 'someSidebar',
frontMatter: {},
sidebarPosition: 0,
previous: {
permalink: '/docs/API/api-overview',
title: 'API Overview',
},
next: {
permalink: '/docs/API/Extension APIs/Theme API',
title: 'Theme API',
},
});
expect(getDocById(version, 'API/Extension APIs/Theme API')).toEqual({
...defaultDocMetadata,
id: 'API/Extension APIs/Theme API',
unversionedId: 'API/Extension APIs/Theme API',
sourceDirName: '3-API/02_Extension APIs',
isDocsHomePage: false,
permalink: '/docs/API/Extension APIs/Theme API',
slug: '/API/Extension APIs/Theme API',
source: path.posix.join(
'@site',
posixPath(path.relative(siteDir, version.contentPath)),
'3-API',
'02_Extension APIs',
'1. Theme API.md',
),
title: 'Theme API',
description: 'Theme API text',
version: 'current',
sidebar: 'someSidebar',
frontMatter: {},
sidebarPosition: 1,
previous: {
permalink: '/docs/API/Extension APIs/Plugin API',
title: 'Plugin API',
},
next: undefined,
});
});
});
describe('site with custom sidebar items generator', () => {
async function loadSite(sidebarItemsGenerator: SidebarItemsGenerator) {
const siteDir = path.join(
__dirname,
'__fixtures__',
'site-with-autogenerated-sidebar',
);
const context = await loadContext(siteDir);
const plugin = pluginContentDocs(
context,
normalizePluginOptions(OptionsSchema, {
path: 'docs',
sidebarItemsGenerator,
}),
);
const content = (await plugin.loadContent?.())!;
return {content, siteDir};
}
test('sidebar is autogenerated according to custom sidebarItemsGenerator', async () => {
const customSidebarItemsGenerator: SidebarItemsGenerator = async () => {
return [
{type: 'doc', id: 'API/api-overview'},
{type: 'doc', id: 'API/api-end'},
];
};
const customSidebarItemsGeneratorMock: SidebarItemsGenerator = jest.fn(
customSidebarItemsGenerator,
);
const {content} = await loadSite(customSidebarItemsGeneratorMock);
const version = content.loadedVersions[0];
expect(version.sidebars).toEqual({
defaultSidebar: [
{type: 'doc', id: 'API/api-overview'},
{type: 'doc', id: 'API/api-end'},
],
});
});
test('sidebarItemsGenerator is called with appropriate data', async () => {
type GeneratorArg = Parameters<SidebarItemsGenerator>[0];
const customSidebarItemsGeneratorMock = jest.fn(
async (_arg: GeneratorArg) => [],
);
const {siteDir} = await loadSite(customSidebarItemsGeneratorMock);
const generatorArg: GeneratorArg =
customSidebarItemsGeneratorMock.mock.calls[0][0];
// Make test pass even if docs are in different order and paths are absolutes
function makeDeterministic(arg: GeneratorArg): GeneratorArg {
return {
...arg,
docs: orderBy(arg.docs, 'id'),
version: {
...arg.version,
contentPath: path.relative(siteDir, arg.version.contentPath),
},
};
}
expect(makeDeterministic(generatorArg)).toMatchSnapshot();
});
});