mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-09 23:27:28 +02:00
chore(v2): make v2 docs plugin legacy (#1639)
* chore(v2): make v2 docs plugin legacy * chore(v2): update fixtures
This commit is contained in:
parent
702dba1c81
commit
e5e085b33d
27 changed files with 24 additions and 21 deletions
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
{
|
||||
"docs": {
|
||||
"Test": [
|
||||
"foo/bar",
|
||||
"foo/baz",
|
||||
{
|
||||
"type": "superman"
|
||||
}
|
||||
],
|
||||
"Guides": [
|
||||
"hello"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -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==
|
|
@ -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
|
|
@ -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
|
|
@ -1,7 +0,0 @@
|
|||
---
|
||||
id: permalink
|
||||
title: Permalink
|
||||
permalink: :baseUrl:docsUrl/endiliey/:id
|
||||
---
|
||||
|
||||
This has a different permalink
|
|
@ -1,20 +0,0 @@
|
|||
{
|
||||
"docs": {
|
||||
"Test": [
|
||||
"foo/bar",
|
||||
"foo/baz",
|
||||
{
|
||||
"type": "link",
|
||||
"label": "Github",
|
||||
"href": "https://github.com"
|
||||
},
|
||||
{
|
||||
"type": "ref",
|
||||
"id": "hello"
|
||||
}
|
||||
],
|
||||
"Guides": [
|
||||
"hello"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -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",
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
|
@ -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',
|
||||
});
|
||||
});
|
||||
});
|
|
@ -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',
|
||||
});
|
||||
});
|
||||
});
|
|
@ -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"`,
|
||||
);
|
||||
});
|
||||
});
|
|
@ -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({});
|
||||
});
|
||||
});
|
|
@ -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,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
};
|
|
@ -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);
|
||||
};
|
|
@ -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;
|
||||
};
|
|
@ -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;
|
||||
};
|
|
@ -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);
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue