chore(v2): make v2 docs plugin legacy (#1639)

* chore(v2): make v2 docs plugin legacy

* chore(v2): update fixtures
This commit is contained in:
Yangshun Tay 2019-07-05 17:20:46 -07:00 committed by GitHub
parent 702dba1c81
commit e5e085b33d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 24 additions and 21 deletions

View file

@ -1,26 +0,0 @@
{
"name": "@docusaurus/plugin-content-docs",
"version": "2.0.0-alpha.19",
"description": "Documentation plugin for Docusaurus",
"main": "src/index.js",
"publishConfig": {
"access": "public"
},
"license": "MIT",
"dependencies": {
"@docusaurus/mdx-loader": "^2.0.0-alpha.19",
"@docusaurus/utils": "^2.0.0-alpha.19",
"fs-extra": "^7.0.1",
"globby": "^9.2.0",
"import-fresh": "^3.0.0",
"loader-utils": "^1.2.3"
},
"peerDependencies": {
"@docusaurus/core": "^2.0.0",
"react": "^16.8.4",
"react-dom": "^16.8.4"
},
"engines": {
"node": ">=8"
}
}

View file

@ -1,14 +0,0 @@
{
"docs": {
"Test": [
"foo/bar",
"foo/baz",
{
"type": "superman"
}
],
"Guides": [
"hello"
]
}
}

View file

@ -1,67 +0,0 @@
---
id: bar
title: Bar
description: This is custom description
---
# Remarkable
> Experience real-time editing with Remarkable!
Click the `clear` link to start with a clean slate, or get the `permalink` to share or save your results.
***
# h1 Heading
## h2 Heading
### h3 Heading
#### h4 Heading
##### h5 Heading
###### h6 Heading
## Horizontal Rules
___
***
***
## Typographic replacements
Enable typographer option to see result.
(c) (C) (r) (R) (tm) (TM) (p) (P) +-
test.. test... test..... test?..... test!....
!!!!!! ???? ,,
Remarkable -- awesome
"Smartypants, double quotes"
'Smartypants, single quotes'
## Emphasis
**This is bold text**
__This is bold text__
*This is italic text*
_This is italic text_
~~Deleted text~~
Superscript: 19^th^
Subscript: H~2~O
++Inserted text++
==Marked text==

View file

@ -1,74 +0,0 @@
---
id: baz
title: baz
---
## Images
Like links, Images also have a footnote style syntax
![Alt text][id]
With a reference later in the document defining the URL location:
[id]: https://octodex.github.com/images/dojocat.jpg "The Dojocat"
## Links
[link text](http://dev.nodeca.com)
[link with title](http://nodeca.github.io/pica/demo/ "title text!")
Autoconverted link https://github.com/nodeca/pica (enable linkify to see)
## Footnotes
Footnote 1 link[^first].
Footnote 2 link[^second].
Inline footnote^[Text of inline footnote] definition.
Duplicated footnote reference[^second].
[^first]: Footnote **can have markup**
and multiple paragraphs.
[^second]: Footnote text.
## Definition lists
Term 1
: Definition 1
with lazy continuation.
Term 2 with *inline markup*
: Definition 2
{ some code, part of Definition 2 }
Third paragraph of definition 2.
_Compact style:_
Term 1
~ Definition 1
Term 2
~ Definition 2a
~ Definition 2b
## Abbreviations
This is HTML abbreviation example.
It converts "HTML", but keep intact partial entries like "xxxHTMLyyy" and so on.
*[HTML]: Hyper Text Markup Language

View file

@ -1,54 +0,0 @@
---
id: hello
title: Hello, World !
---
Hi, Endilie here :)
## Relative links
Replace this
[foo](foo/bar.md)
Can't replace this
[file](file.md)
Do not replace below
```
[hello](hello.md)
```
## Blockquotes
> Blockquotes can also be nested...
>> ...by using additional greater-than signs right next to each other...
> > > ...or with spaces between arrows.
## Lists
Unordered
+ Create a list by starting a line with `+`, `-`, or `*`
+ Sub-lists are made by indenting 2 spaces:
- Marker character change forces new list start:
* Ac tristique libero volutpat at
+ Facilisis in pretium nisl aliquet
- Nulla volutpat aliquam velit
+ Very easy!
Ordered
1. Lorem ipsum dolor sit amet
2. Consectetur adipiscing elit
3. Integer molestie lorem at massa
1. You can use sequential numbers...
1. ...or keep all the numbers as `1.`
Start numbering with offset:
57. foo
1. bar

View file

@ -1,7 +0,0 @@
---
id: permalink
title: Permalink
permalink: :baseUrl:docsUrl/endiliey/:id
---
This has a different permalink

View file

@ -1,20 +0,0 @@
{
"docs": {
"Test": [
"foo/bar",
"foo/baz",
{
"type": "link",
"label": "Github",
"href": "https://github.com"
},
{
"type": "ref",
"id": "hello"
}
],
"Guides": [
"hello"
]
}
}

View file

@ -1,41 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`loadSidebars sidebars with known sidebar item type 1`] = `
Object {
"docs": Array [
Object {
"items": Array [
Object {
"id": "foo/bar",
"type": "doc",
},
Object {
"id": "foo/baz",
"type": "doc",
},
Object {
"href": "https://github.com",
"label": "Github",
"type": "link",
},
Object {
"id": "hello",
"type": "ref",
},
],
"label": "Test",
"type": "category",
},
Object {
"items": Array [
Object {
"id": "hello",
"type": "doc",
},
],
"label": "Guides",
"type": "category",
},
],
}
`;

View file

@ -1,57 +0,0 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import path from 'path';
import pluginContentDocs from '../index';
describe('loadDocs', () => {
test('simple website', async () => {
const siteDir = path.join(__dirname, '__fixtures__', 'website');
const siteConfig = {
title: 'Hello',
baseUrl: '/',
url: 'https://docusaurus.io',
};
const sidebarPath = path.join(siteDir, 'sidebars.json');
const plugin = pluginContentDocs(
{
siteDir,
siteConfig,
},
{
path: 'docs',
sidebarPath,
},
);
const {docs: docsMetadata} = await plugin.loadContent();
const docsDir = plugin.contentPath;
expect(docsMetadata.hello).toEqual({
category: 'Guides',
id: 'hello',
permalink: '/docs/hello',
previous: 'foo/baz',
previous_title: 'baz',
sidebar: 'docs',
source: path.join(docsDir, 'hello.md'),
title: 'Hello, World !',
description: `Hi, Endilie here :)`,
});
expect(docsMetadata['foo/bar']).toEqual({
category: 'Test',
id: 'foo/bar',
next: 'foo/baz',
next_title: 'baz',
permalink: '/docs/foo/bar',
sidebar: 'docs',
source: path.join(docsDir, 'foo', 'bar.md'),
title: 'Bar',
description: 'This is custom description',
});
});
});

View file

@ -1,64 +0,0 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import path from 'path';
import processMetadata from '../metadata';
describe('processMetadata', () => {
const siteDir = path.join(__dirname, '__fixtures__', 'website');
const siteConfig = {
title: 'Hello',
baseUrl: '/',
url: 'https://docusaurus.io',
};
const docsDir = path.resolve(siteDir, 'docs');
test('normal docs', async () => {
const sourceA = path.join('foo', 'bar.md');
const sourceB = path.join('hello.md');
const dataA = await processMetadata(
sourceA,
docsDir,
{},
siteConfig,
'docs',
);
const dataB = await processMetadata(
sourceB,
docsDir,
{},
siteConfig,
'docs',
);
expect(dataA).toEqual({
id: 'foo/bar',
permalink: '/docs/foo/bar',
source: path.join(docsDir, sourceA),
title: 'Bar',
description: 'This is custom description',
});
expect(dataB).toEqual({
id: 'hello',
permalink: '/docs/hello',
source: path.join(docsDir, sourceB),
title: 'Hello, World !',
description: `Hi, Endilie here :)`,
});
});
test('docs with custom permalink', async () => {
const source = path.join('permalink.md');
const data = await processMetadata(source, docsDir, {}, siteConfig, 'docs');
expect(data).toEqual({
id: 'permalink',
permalink: '/docs/endiliey/permalink',
source: path.join(docsDir, source),
title: 'Permalink',
description: 'This has a different permalink',
});
});
});

View file

@ -1,260 +0,0 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import createOrder from '../order';
describe('createOrder', () => {
test('multiple sidebars with subcategory', () => {
const result = createOrder({
docs: [
{
type: 'category',
label: 'Category1',
items: [
{
type: 'category',
label: 'Subcategory 1',
items: [{type: 'doc', id: 'doc1'}],
},
{
type: 'category',
label: 'Subcategory 2',
items: [{type: 'doc', id: 'doc2'}],
},
],
},
{
type: 'category',
label: 'Category2',
items: [{type: 'doc', id: 'doc3'}, {type: 'doc', id: 'doc4'}],
},
],
otherDocs: [
{
type: 'category',
label: 'Category1',
items: [{type: 'doc', id: 'doc5'}],
},
],
});
expect(result).toEqual({
doc1: {
category: 'Category1',
subCategory: 'Subcategory 1',
next: 'doc2',
previous: undefined,
sidebar: 'docs',
},
doc2: {
category: 'Category1',
subCategory: 'Subcategory 2',
next: 'doc3',
previous: 'doc1',
sidebar: 'docs',
},
doc3: {
category: 'Category2',
subCategory: undefined,
next: 'doc4',
previous: 'doc2',
sidebar: 'docs',
},
doc4: {
category: 'Category2',
subCategory: undefined,
next: undefined,
previous: 'doc3',
sidebar: 'docs',
},
doc5: {
category: 'Category1',
subCategory: undefined,
next: undefined,
previous: undefined,
sidebar: 'otherDocs',
},
});
});
test('multiple sidebars without subcategory', () => {
const result = createOrder({
docs: [
{
type: 'category',
label: 'Category1',
items: [{type: 'doc', id: 'doc1'}, {type: 'doc', id: 'doc2'}],
},
{
type: 'category',
label: 'Category2',
items: [{type: 'doc', id: 'doc3'}, {type: 'doc', id: 'doc4'}],
},
],
otherDocs: [
{
type: 'category',
label: 'Category1',
items: [{type: 'doc', id: 'doc5'}],
},
],
});
expect(result).toEqual({
doc1: {
category: 'Category1',
subCategory: undefined,
next: 'doc2',
previous: undefined,
sidebar: 'docs',
},
doc2: {
category: 'Category1',
subCategory: undefined,
next: 'doc3',
previous: 'doc1',
sidebar: 'docs',
},
doc3: {
category: 'Category2',
subCategory: undefined,
next: 'doc4',
previous: 'doc2',
sidebar: 'docs',
},
doc4: {
category: 'Category2',
subCategory: undefined,
next: undefined,
previous: 'doc3',
sidebar: 'docs',
},
doc5: {
category: 'Category1',
subCategory: undefined,
next: undefined,
previous: undefined,
sidebar: 'otherDocs',
},
});
});
test('versioned sidebars', () => {
const result = createOrder({
docs: [
{
type: 'category',
label: 'Category1',
items: [{type: 'doc', id: 'doc1'}],
},
],
'version-1.2.3-docs': [
{
type: 'category',
label: 'Category1',
items: [{type: 'doc', id: 'version-1.2.3-doc2'}],
},
{
type: 'category',
label: 'Category2',
items: [{type: 'doc', id: 'version-1.2.3-doc1'}],
},
],
});
expect(result).toEqual({
doc1: {
category: 'Category1',
subCategory: undefined,
next: undefined,
previous: undefined,
sidebar: 'docs',
},
'version-1.2.3-doc1': {
category: 'Category2',
subCategory: undefined,
next: undefined,
previous: 'version-1.2.3-doc2',
sidebar: 'version-1.2.3-docs',
},
'version-1.2.3-doc2': {
category: 'Category1',
subCategory: undefined,
next: 'version-1.2.3-doc1',
previous: undefined,
sidebar: 'version-1.2.3-docs',
},
});
});
test('multiple sidebars with subcategories, refs and external links', () => {
const result = createOrder({
docs: [
{
type: 'category',
label: 'Category1',
items: [
{
type: 'category',
label: 'Subcategory 1',
items: [{type: 'link', href: '//example.com', label: 'bar'}],
},
{
type: 'category',
label: 'Subcategory 2',
items: [{type: 'doc', id: 'doc2'}],
},
{
type: 'category',
label: 'Subcategory 1',
items: [{type: 'link', href: '//example2.com', label: 'baz'}],
},
],
},
{
type: 'category',
label: 'Category2',
items: [{type: 'doc', id: 'doc3'}, {type: 'ref', id: 'doc4'}],
},
],
otherDocs: [
{
type: 'category',
label: 'Category1',
items: [{type: 'doc', id: 'doc5'}],
},
],
});
expect(result).toEqual({
doc2: {
category: 'Category1',
subCategory: 'Subcategory 2',
next: 'doc3',
previous: undefined,
sidebar: 'docs',
},
doc3: {
category: 'Category2',
subCategory: undefined,
next: undefined,
previous: 'doc2',
sidebar: 'docs',
},
doc5: {
category: 'Category1',
subCategory: undefined,
next: undefined,
previous: undefined,
sidebar: 'otherDocs',
},
});
});
test('edge cases', () => {
expect(createOrder({})).toEqual({});
expect(createOrder(undefined)).toEqual({});
expect(() => createOrder(null)).toThrowErrorMatchingInlineSnapshot(
`"Cannot convert undefined or null to object"`,
);
});
});

View file

@ -1,41 +0,0 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import path from 'path';
import loadSidebars from '../sidebars';
/* eslint-disable global-require, import/no-dynamic-require */
describe('loadSidebars', () => {
test('sidebars with known sidebar item type', async () => {
const sidebarPath = path.join(
__dirname,
'__fixtures__',
'website',
'sidebars.json',
);
const result = loadSidebars(sidebarPath);
expect(result).toMatchSnapshot();
});
test('sidebars with unknown sidebar item type', async () => {
const sidebarPath = path.join(
__dirname,
'__fixtures__',
'website',
'bad-sidebars.json',
);
expect(() => loadSidebars(sidebarPath)).toThrowErrorMatchingInlineSnapshot(
`"Unknown sidebar item type: superman"`,
);
});
test('no sidebars', () => {
const result = loadSidebars(null);
expect(result).toEqual({});
});
});

View file

@ -1,191 +0,0 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const globby = require('globby');
const fs = require('fs');
const path = require('path');
const {idx, normalizeUrl, docuHash} = require('@docusaurus/utils');
const createOrder = require('./order');
const loadSidebars = require('./sidebars');
const processMetadata = require('./metadata');
const DEFAULT_OPTIONS = {
path: 'docs', // Path to data on filesystem, relative to site dir.
routeBasePath: 'docs', // URL Route.
include: ['**/*.md', '**/*.mdx'], // Extensions to include.
// TODO: Change format to array.
sidebarPath: '', // Path to sidebar configuration for showing a list of markdown pages.
// TODO: Settle themeing.
docLayoutComponent: '@theme/DocPage',
docItemComponent: '@theme/DocItem',
remarkPlugins: [],
rehypePlugins: [],
};
module.exports = function(context, opts) {
const options = {...DEFAULT_OPTIONS, ...opts};
const contentPath = path.resolve(context.siteDir, options.path);
let globalContents = {};
return {
name: 'docusaurus-plugin-content-docs',
contentPath,
getPathsToWatch() {
const {include = []} = options;
const globPattern = include.map(pattern => `${contentPath}/${pattern}`);
return [...globPattern, options.sidebarPath];
},
// Fetches blog contents and returns metadata for the contents.
async loadContent() {
const {include, routeBasePath, sidebarPath} = options;
const {siteConfig} = context;
const docsDir = contentPath;
if (!fs.existsSync(docsDir)) {
return null;
}
const docsSidebars = loadSidebars(sidebarPath);
// Build the docs ordering such as next, previous, category and sidebar
const order = createOrder(docsSidebars);
// Prepare metadata container.
const docs = {};
// Metadata for default docs files.
const docsFiles = await globby(include, {
cwd: docsDir,
});
await Promise.all(
docsFiles.map(async source => {
const metadata = await processMetadata(
source,
docsDir,
order,
siteConfig,
routeBasePath,
);
docs[metadata.id] = metadata;
}),
);
// Get the titles of the previous and next ids so that we can use them.
Object.keys(docs).forEach(currentID => {
const previousID = idx(docs, [currentID, 'previous']);
if (previousID) {
const previousTitle = idx(docs, [previousID, 'title']);
docs[currentID].previous_title = previousTitle || 'Previous';
}
const nextID = idx(docs, [currentID, 'next']);
if (nextID) {
const nextTitle = idx(docs, [nextID, 'title']);
docs[currentID].next_title = nextTitle || 'Next';
}
});
const sourceToPermalink = {};
const permalinkToId = {};
Object.values(docs).forEach(({id, source, permalink}) => {
sourceToPermalink[source] = permalink;
permalinkToId[permalink] = id;
});
globalContents = {
docs,
docsDir,
docsSidebars,
sourceToPermalink,
permalinkToId,
};
return globalContents;
},
async contentLoaded({content, actions}) {
if (!content) {
return;
}
const {docLayoutComponent, docItemComponent, routeBasePath} = options;
const {addRoute, createData} = actions;
const routes = await Promise.all(
Object.values(content.docs).map(async metadataItem => {
const metadataPath = await createData(
`${docuHash(metadataItem.permalink)}.json`,
JSON.stringify(metadataItem, null, 2),
);
return {
path: metadataItem.permalink,
component: docItemComponent,
exact: true,
modules: {
content: metadataItem.source,
metadata: metadataPath,
},
};
}),
);
const docsBaseRoute = normalizeUrl([
context.siteConfig.baseUrl,
routeBasePath,
]);
const docsMetadataPath = await createData(
`${docuHash(docsBaseRoute)}.json`,
JSON.stringify(content, null, 2),
);
addRoute({
path: docsBaseRoute,
component: docLayoutComponent,
routes,
modules: {
docsMetadata: docsMetadataPath,
},
});
},
configureWebpack(config, isServer, {getBabelLoader, getCacheLoader}) {
const {rehypePlugins, remarkPlugins} = options;
return {
module: {
rules: [
{
test: /(\.mdx?)$/,
include: [contentPath],
use: [
getCacheLoader(isServer),
getBabelLoader(isServer),
{
loader: '@docusaurus/mdx-loader',
options: {
remarkPlugins,
rehypePlugins,
},
},
{
loader: path.resolve(__dirname, './markdown/index.js'),
options: {
siteConfig: context.siteConfig,
docsDir: globalContents.docsDir,
sourceToPermalink: globalContents.sourceToPermalink,
},
},
],
},
],
},
};
},
};
};

View file

@ -1,60 +0,0 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const {getOptions} = require('loader-utils');
const {resolve} = require('url');
module.exports = async function(fileString) {
const callback = this.async();
const options = Object.assign({}, getOptions(this), {
filepath: this.resourcePath,
});
const {docsDir, sourceToPermalink} = options;
// Determine the source dir. e.g: /docs, /website/versioned_docs/version-1.0.0
let sourceDir;
const thisSource = this.resourcePath;
if (thisSource.startsWith(docsDir)) {
sourceDir = docsDir;
}
let content = fileString;
// Replace internal markdown linking (except in fenced blocks).
if (sourceDir) {
let fencedBlock = false;
const lines = content.split('\n').map(line => {
if (line.trim().startsWith('```')) {
fencedBlock = !fencedBlock;
}
if (fencedBlock) return line;
let modifiedLine = line;
// Replace inline-style links or reference-style links e.g:
// This is [Document 1](doc1.md) -> we replace this doc1.md with correct link
// [doc1]: doc1.md -> we replace this doc1.md with correct link
const mdRegex = /(?:(?:\]\()|(?:\]:\s?))(?!https)([^'")\]\s>]+\.md)/g;
let mdMatch = mdRegex.exec(modifiedLine);
while (mdMatch !== null) {
// Replace it to correct html link.
const mdLink = mdMatch[1];
const targetSource = `${sourceDir}/${mdLink}`;
const permalink =
sourceToPermalink[resolve(thisSource, mdLink)] ||
sourceToPermalink[targetSource];
if (permalink) {
modifiedLine = modifiedLine.replace(mdLink, permalink);
}
mdMatch = mdRegex.exec(modifiedLine);
}
return modifiedLine;
});
content = lines.join('\n');
}
return callback(null, content);
};

View file

@ -1,83 +0,0 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const fs = require('fs-extra');
const path = require('path');
const {parse, normalizeUrl} = require('@docusaurus/utils');
module.exports = async function processMetadata(
source,
refDir,
order,
siteConfig,
docsBasePath,
) {
const filepath = path.resolve(refDir, source);
const fileString = await fs.readFile(filepath, 'utf-8');
const {frontMatter: metadata = {}, excerpt} = parse(fileString);
// Default id is the file name.
if (!metadata.id) {
metadata.id = path.basename(source, path.extname(source));
}
if (metadata.id.includes('/')) {
throw new Error('Document id cannot include "/".');
}
// Default title is the id.
if (!metadata.title) {
metadata.title = metadata.id;
}
if (!metadata.description) {
metadata.description = excerpt;
}
const dirName = path.dirname(source);
if (dirName !== '.') {
const prefix = dirName;
if (prefix) {
metadata.id = `${prefix}/${metadata.id}`;
}
}
// The docs absolute file source.
// e.g: `/end/docs/hello.md` or `/end/website/versioned_docs/version-1.0.0/hello.md`
metadata.source = path.join(refDir, source);
// Build the permalink.
const {baseUrl} = siteConfig;
// If user has own custom permalink defined in frontmatter
// e.g: :baseUrl:docsUrl/:langPart/:versionPart/endiliey/:id
if (metadata.permalink) {
metadata.permalink = path.resolve(
metadata.permalink
.replace(/:baseUrl/, baseUrl)
.replace(/:docsUrl/, docsBasePath)
.replace(/:id/, metadata.id),
);
} else {
metadata.permalink = normalizeUrl([baseUrl, docsBasePath, metadata.id]);
}
// Determine order.
const {id} = metadata;
if (order[id]) {
metadata.sidebar = order[id].sidebar;
metadata.category = order[id].category;
metadata.subCategory = order[id].subCategory;
if (order[id].next) {
metadata.next = order[id].next;
}
if (order[id].previous) {
metadata.previous = order[id].previous;
}
}
return metadata;
};

View file

@ -1,72 +0,0 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
// Build the docs meta such as next, previous, category and sidebar.
module.exports = function createOrder(allSidebars = {}) {
const order = {};
Object.keys(allSidebars).forEach(sidebarId => {
const sidebar = allSidebars[sidebarId];
const ids = [];
const categoryOrder = [];
const subCategoryOrder = [];
const indexItems = ({items, categoryLabel, subCategoryLabel}) => {
items.forEach(item => {
switch (item.type) {
case 'category':
indexItems({
items: item.items,
categoryLabel: categoryLabel || item.label,
subCategoryLabel: categoryLabel && item.label,
});
break;
case 'ref':
case 'link':
// Refs and links should not be shown in navigation.
break;
case 'doc':
ids.push(item.id);
categoryOrder.push(categoryLabel);
subCategoryOrder.push(subCategoryLabel);
break;
default:
throw new Error(
`Unknown item type: ${item.type}. Item: ${JSON.stringify(item)}`,
);
}
});
};
indexItems({items: sidebar});
// eslint-disable-next-line
for (let i = 0; i < ids.length; i++) {
const id = ids[i];
let previous;
let next;
if (i > 0) {
previous = ids[i - 1];
}
if (i < ids.length - 1) {
next = ids[i + 1];
}
order[id] = {
previous,
next,
sidebar: sidebarId,
category: categoryOrder[i],
subCategory: subCategoryOrder[i],
};
}
});
return order;
};

View file

@ -1,122 +0,0 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const fs = require('fs');
const importFresh = require('import-fresh');
/**
* Check that item contains only allowed keys
*
* @param {Object} item
* @param {Array<string>} keys
*/
function assertItem(item, keys) {
const unknownKeys = Object.keys(item).filter(
key => !keys.includes(key) && key !== 'type',
);
if (unknownKeys.length) {
throw new Error(
`Unknown sidebar item keys: ${unknownKeys}. Item: ${JSON.stringify(
item,
)}`,
);
}
}
/**
* Normalizes recursively category and all its children. Ensures, that at the end
* each item will be an object with the corresponding type
*
* @param {Array<Object>} category
* @param {number} [level=0]
*
* @return {Array<Object>}
*/
function normalizeCategory(category, level = 0) {
if (level === 2) {
throw new Error(
`Can not process ${
category.label
} category. Categories can be nested only one level deep.`,
);
}
assertItem(category, ['items', 'label']);
if (!Array.isArray(category.items)) {
throw new Error(
`Error loading ${category.label} category. Category items must be array.`,
);
}
const items = category.items.map(item => {
switch (item.type) {
case 'category':
return normalizeCategory(item, level + 1);
case 'link':
assertItem(item, ['href', 'label']);
break;
case 'ref':
assertItem(item, ['id', 'label']);
break;
default:
if (typeof item === 'string') {
return {
type: 'doc',
id: item,
};
}
if (item.type !== 'doc') {
throw new Error(`Unknown sidebar item type: ${item.type}`);
}
assertItem(item, ['id', 'label']);
break;
}
return item;
});
return {...category, items};
}
/**
* Converts sidebars object to mapping to arrays of sidebar item objects
*
* @param {{[key: string]: Object}} sidebars
*
* @return {{[key: string]: Array<Object>}}
*/
function normalizeSidebar(sidebars) {
return Object.entries(sidebars).reduce((acc, [sidebarId, sidebar]) => {
let normalizedSidebar = sidebar;
if (!Array.isArray(sidebar)) {
// convert sidebar to a more generic structure
normalizedSidebar = Object.entries(sidebar).map(([label, items]) => ({
type: 'category',
label,
items,
}));
}
acc[sidebarId] = normalizedSidebar.map(item => normalizeCategory(item));
return acc;
}, {});
}
module.exports = function loadSidebars(sidebarPath) {
// We don't want sidebars to be cached because of hotreloading.
let allSidebars = {};
if (sidebarPath && fs.existsSync(sidebarPath)) {
allSidebars = importFresh(sidebarPath);
}
return normalizeSidebar(allSidebars);
};