Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(v2): allow nested sidebar category shorthand syntax #2444

Merged
merged 3 commits into from
Mar 25, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@ module.exports = {
transform: {
'^.+\\.[jt]sx?$': 'babel-jest',
},
setupFiles: ['./jest/stylelint-rule-test.js'],
setupFiles: ['./jest/stylelint-rule-test.js', 'array-flat-polyfill'],
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
* 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.
*/

module.exports = {
docs: [
{
'level 1': [
'a',
{
'level 2': [
{
'level 3': [
'c',
{
'level 4': [
'd',
{
'deeper more more': ['e'],
},
],
},
],
},
'f',
],
},
],
},
],
};

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,17 @@ describe('loadSidebars', () => {
expect(result).toMatchSnapshot();
});

test('sidebars shortand and longform lead to exact same sidebar', async () => {
const sidebarPath1 = path.join(fixtureDir, 'sidebars-category.js');
const sidebarPath2 = path.join(
fixtureDir,
'sidebars-category-shorthand.js',
);
const sidebar1 = loadSidebars([sidebarPath1]);
const sidebar2 = loadSidebars([sidebarPath2]);
expect(sidebar1).toEqual(sidebar2);
});

test('sidebars with category but category.items is not an array', async () => {
const sidebarPath = path.join(
fixtureDir,
Expand Down Expand Up @@ -93,15 +104,6 @@ describe('loadSidebars', () => {
);
});

test('sidebars with invalid sidebar item', async () => {
const sidebarPath = path.join(fixtureDir, 'sidebars-invalid-item.json');
expect(() =>
loadSidebars([sidebarPath]),
).toThrowErrorMatchingInlineSnapshot(
`"Unknown sidebar item \\"{\\"a\\":\\"b\\",\\"c\\":\\"d\\"}\\"."`,
);
});

test('sidebars with unknown sidebar item type', async () => {
const sidebarPath = path.join(fixtureDir, 'sidebars-unknown-type.json');
expect(() =>
Expand Down
61 changes: 37 additions & 24 deletions packages/docusaurus-plugin-content-docs/src/sidebars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,28 @@ import {
SidebarItemRaw,
SidebarItemLink,
SidebarItemDoc,
SidebarCategoryShorthandRaw,
} from './types';

function isCategoryShorthand(
item: SidebarItemRaw,
): item is SidebarCategoryShorthandRaw {
return typeof item !== 'string' && !item.type;
}

/**
* Convert {category1: [item1,item2]} shorthand syntax to long-form syntax
*/
function normalizeCategoryShorthand(
sidebar: SidebarCategoryShorthandRaw,
): SidebarItemCategoryRaw[] {
return Object.entries(sidebar).map(([label, items]) => ({
type: 'category',
label,
items,
}));
}

/**
* Check that item contains only allowed keys.
*/
Expand Down Expand Up @@ -75,27 +95,29 @@ function assertIsLink(item: any): asserts item is SidebarItemLink {
* Normalizes recursively item and all its children. Ensures that at the end
* each item will be an object with the corresponding type.
*/
function normalizeItem(item: SidebarItemRaw): SidebarItem {
function normalizeItem(item: SidebarItemRaw): SidebarItem[] {
if (typeof item === 'string') {
return {
type: 'doc',
id: item,
};
return [
{
type: 'doc',
id: item,
},
];
}
if (!item.type) {
throw new Error(`Unknown sidebar item "${JSON.stringify(item)}".`);
if (isCategoryShorthand(item)) {
return normalizeCategoryShorthand(item).flatMap(normalizeItem);
}
switch (item.type) {
case 'category':
assertIsCategory(item);
return {...item, items: item.items.map(normalizeItem)};
return [{...item, items: item.items.flatMap(normalizeItem)}];
case 'link':
assertIsLink(item);
return item;
return [item];
case 'ref':
case 'doc':
assertIsDoc(item);
return item;
return [item];
default:
throw new Error(`Unknown sidebar item type: ${item.type}`);
}
Expand All @@ -107,20 +129,11 @@ function normalizeItem(item: SidebarItemRaw): SidebarItem {
function normalizeSidebar(sidebars: SidebarRaw): Sidebar {
return Object.entries(sidebars).reduce(
(acc: Sidebar, [sidebarId, sidebar]) => {
let normalizedSidebar: SidebarItemRaw[];

if (!Array.isArray(sidebar)) {
// Convert sidebar to a more generic structure.
normalizedSidebar = Object.entries(sidebar).map(([label, items]) => ({
type: 'category',
label,
items,
}));
} else {
normalizedSidebar = sidebar;
}

acc[sidebarId] = normalizedSidebar.map(normalizeItem);
const normalizedSidebar: SidebarItemRaw[] = Array.isArray(sidebar)
? sidebar
: normalizeCategoryShorthand(sidebar);

acc[sidebarId] = normalizedSidebar.flatMap(normalizeItem);

return acc;
},
Expand Down
11 changes: 6 additions & 5 deletions packages/docusaurus-plugin-content-docs/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export type SidebarItem =

export type SidebarItemRaw =
| string
| SidebarCategoryShorthandRaw
| SidebarItemDoc
| SidebarItemLink
| SidebarItemCategoryRaw
Expand All @@ -63,13 +64,13 @@ export type SidebarItemRaw =
[key: string]: any;
};

export interface SidebarCategoryShorthandRaw {
[sidebarCategory: string]: SidebarItemRaw[];
}

// Sidebar given by user that is not normalized yet. e.g: sidebars.json
export interface SidebarRaw {
[sidebarId: string]:
| {
[sidebarCategory: string]: SidebarItemRaw[];
}
| SidebarItemRaw[];
[sidebarId: string]: SidebarCategoryShorthandRaw | SidebarItemRaw[];
}

export interface Sidebar {
Expand Down
1 change: 1 addition & 0 deletions packages/docusaurus/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"@babel/runtime": "^7.7.4",
"@docusaurus/utils": "^2.0.0-alpha.48",
"@endiliey/static-site-generator-webpack-plugin": "^4.0.0",
"array-flat-polyfill": "^1.0.1",
"babel-loader": "^8.0.6",
"babel-plugin-dynamic-import-node": "^2.3.0",
"cache-loader": "^4.1.0",
Expand Down
2 changes: 2 additions & 0 deletions packages/docusaurus/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
* LICENSE file in the root directory of this source tree.
*/

import 'array-flat-polyfill';

export {build} from './commands/build';
export {start} from './commands/start';
export {swizzle} from './commands/swizzle';
Expand Down
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"compilerOptions": {
"target": "es2017",
"module": "commonjs",
"lib": ["es2017"],
"lib": ["es2017","es2019.array"],
"declaration": true,
"declarationMap": true,

Expand Down
20 changes: 18 additions & 2 deletions website/docs/sidebar.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ module.exports = {
};
```

If you don't want to rely on iteration order of JavaScript object keys for the category name, the following sidebar object is also equivalent of the above.
Keep in mind that EcmaScript does not guarantee `Object.keys({a,b}) === ['a','b']` (yet, this is generally true). If you don't want to rely on iteration order of JavaScript object keys for the category name, the following sidebar object is also equivalent of the above shorthand syntax.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will try to find a better text for this, as it seems specified in ES6


```js
// sidebars.js
Expand Down Expand Up @@ -221,7 +221,23 @@ module.exports = {
{
type: 'category',
label: 'Docs',
items: ['markdown-features', 'sidebar'],
items: ['markdown-features', 'sidebar', 'versioning'],
},
],
},
};
```

**Note**: it's possible to use the shorthand syntax to create nested categories:

```js
// sidebars.js
module.exports = {
docs: {
Guides: [
'creating-pages',
{
Docs: ['markdown-features', 'sidebar', 'versioning'],
},
],
},
Expand Down
4 changes: 1 addition & 3 deletions website/sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@ module.exports = {
'styling-layout',
'static-assets',
{
type: 'category',
label: 'Docs',
items: ['markdown-features', 'sidebar', 'versioning'],
Docs: ['markdown-features', 'sidebar', 'versioning'],
},
'blog',
'search',
Expand Down
Loading