feat(v2): introduce docs slug in front matter (#2771)

* feat: docs pathname frontmatter (for #2697)

* feat: docs pathname frontmatter (for #2697)

* chore: comment typo

* feat: add slug frontmatter for docs

* test: add tests for versioned sites slugs

* docs: document slug feature

* test: fix tests and snapshots about doc slug feature

* docs(v2): doc slug wording

* Update website/docs/docs.md

Co-authored-by: Alexey Pyltsyn <lex61rus@gmail.com>

Co-authored-by: Alexey Pyltsyn <lex61rus@gmail.com>
This commit is contained in:
Sébastien Lorber 2020-06-02 19:50:30 +02:00 committed by GitHub
parent a32422caa2
commit b8de9c6ded
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 71 additions and 24 deletions

View file

@ -0,0 +1,5 @@
---
slug: hello/super
---
Lorem

View file

@ -1,6 +1,7 @@
---
id: baz
title: baz
slug: bazSlug.html
---
## Images

View file

@ -1 +1,4 @@
---
slug: barSlug
---
This is `next` version of bar.

View file

@ -14,7 +14,7 @@ Object {
"type": "link",
},
Object {
"href": "/docs/foo/baz",
"href": "/docs/foo/bazSlug.html",
"label": "baz",
"type": "link",
},
@ -85,7 +85,7 @@ Array [
"modules": Object {
"content": "@site/docs/foo/baz.md",
},
"path": "/docs/foo/baz",
"path": "/docs/foo/bazSlug.html",
},
Object {
"component": "@theme/DocItem",
@ -159,7 +159,7 @@ Array [
"modules": Object {
"content": "@site/versioned_docs/version-1.0.0/foo/bar.md",
},
"path": "/docs/1.0.0/foo/bar",
"path": "/docs/1.0.0/foo/barSlug",
},
Object {
"component": "@theme/DocItem",
@ -193,7 +193,7 @@ Array [
"modules": Object {
"content": "@site/docs/foo/bar.md",
},
"path": "/docs/next/foo/bar",
"path": "/docs/next/foo/barSlug",
},
Object {
"component": "@theme/DocItem",
@ -241,7 +241,7 @@ Object {
"collapsed": true,
"items": Array [
Object {
"href": "/docs/next/foo/bar",
"href": "/docs/next/foo/barSlug",
"label": "bar",
"type": "link",
},
@ -267,7 +267,7 @@ Object {
"collapsed": true,
"items": Array [
Object {
"href": "/docs/1.0.0/foo/bar",
"href": "/docs/1.0.0/foo/barSlug",
"label": "bar",
"type": "link",
},
@ -330,7 +330,7 @@ Object {
"collapsed": true,
"items": Array [
Object {
"href": "/docs/1.0.0/foo/bar",
"href": "/docs/1.0.0/foo/barSlug",
"label": "bar",
"type": "link",
},
@ -358,7 +358,7 @@ Object {
],
},
"permalinkToSidebar": Object {
"/docs/1.0.0/foo/bar": "version-1.0.0/docs",
"/docs/1.0.0/foo/barSlug": "version-1.0.0/docs",
"/docs/1.0.0/foo/baz": "version-1.0.0/docs",
"/docs/1.0.0/hello": "version-1.0.0/docs",
},
@ -412,7 +412,7 @@ Object {
"collapsed": true,
"items": Array [
Object {
"href": "/docs/next/foo/bar",
"href": "/docs/next/foo/barSlug",
"label": "bar",
"type": "link",
},
@ -435,7 +435,7 @@ Object {
],
},
"permalinkToSidebar": Object {
"/docs/next/foo/bar": "docs",
"/docs/next/foo/barSlug": "docs",
"/docs/next/hello": "docs",
},
"version": "next",

View file

@ -163,7 +163,7 @@ describe('simple website', () => {
permalink: '/docs/hello',
previous: {
title: 'baz',
permalink: '/docs/foo/baz',
permalink: '/docs/foo/bazSlug.html',
},
sidebar: 'docs',
source: path.join('@site', pluginPath, 'hello.md'),
@ -175,7 +175,7 @@ describe('simple website', () => {
id: 'foo/bar',
next: {
title: 'baz',
permalink: '/docs/foo/baz',
permalink: '/docs/foo/bazSlug.html',
},
permalink: '/docs/foo/bar',
sidebar: 'docs',
@ -300,7 +300,7 @@ describe('versioned website', () => {
expect(docsMetadata['version-1.0.1/foo/baz']).toBeUndefined();
expect(docsMetadata['foo/bar']).toEqual({
id: 'foo/bar',
permalink: '/docs/next/foo/bar',
permalink: '/docs/next/foo/barSlug',
source: path.join('@site', routeBasePath, 'foo', 'bar.md'),
title: 'bar',
description: 'This is next version of bar.',
@ -321,7 +321,7 @@ describe('versioned website', () => {
sidebar: 'docs',
previous: {
title: 'bar',
permalink: '/docs/next/foo/bar',
permalink: '/docs/next/foo/barSlug',
},
});
expect(docsMetadata['version-1.0.1/hello']).toEqual({
@ -363,7 +363,7 @@ describe('versioned website', () => {
},
previous: {
title: 'bar',
permalink: '/docs/1.0.0/foo/bar',
permalink: '/docs/1.0.0/foo/barSlug',
},
});

View file

@ -79,7 +79,7 @@ describe('simple site', () => {
expect(data).toEqual({
id: 'foo/baz',
permalink: '/docs/foo/baz',
permalink: '/docs/foo/bazSlug.html',
source: path.join('@site', routeBasePath, source),
title: 'baz',
editUrl:
@ -172,7 +172,7 @@ describe('simple site', () => {
});
test('docs with invalid id', async () => {
const badSiteDir = path.join(fixtureDir, 'bad-site');
const badSiteDir = path.join(fixtureDir, 'bad-id-site');
const options = {
routeBasePath,
};
@ -189,6 +189,25 @@ describe('simple site', () => {
),
);
});
test('docs with invalid slug', async () => {
const badSiteDir = path.join(fixtureDir, 'bad-slug-site');
const options = {
routeBasePath,
};
return processMetadata({
source: 'invalid-slug.md',
refDir: path.join(badSiteDir, 'docs'),
context,
options,
env,
}).catch((e) =>
expect(e).toMatchInlineSnapshot(
`[Error: Document slug cannot include "/".]`,
),
);
});
});
describe('versioned site', () => {
@ -225,7 +244,7 @@ describe('versioned site', () => {
expect(dataA).toEqual({
id: 'foo/bar',
permalink: '/docs/next/foo/bar',
permalink: '/docs/next/foo/barSlug',
source: path.join('@site', routeBasePath, sourceA),
title: 'bar',
description: 'This is next version of bar.',
@ -283,7 +302,7 @@ describe('versioned site', () => {
expect(dataA).toEqual({
id: 'version-1.0.0/foo/bar',
permalink: '/docs/1.0.0/foo/bar',
permalink: '/docs/1.0.0/foo/barSlug',
source: path.join('@site', path.relative(siteDir, versionedDir), sourceA),
title: 'bar',
description: 'Bar 1.0.0 !',

View file

@ -98,13 +98,18 @@ export default async function processMetadata({
// Default base id is the file name.
const baseID: string =
frontMatter.id || path.basename(source, path.extname(source));
if (baseID.includes('/')) {
throw new Error('Document id cannot include "/".');
}
// Append subdirectory as part of id.
const baseSlug: string = frontMatter.slug || baseID;
if (baseSlug.includes('/')) {
throw new Error('Document slug cannot include "/".');
}
// Append subdirectory as part of id/slug.
const id = dirName !== '.' ? `${dirName}/${baseID}` : baseID;
const slug = dirName !== '.' ? `${dirName}/${baseSlug}` : baseSlug;
// Default title is the id.
const title: string = frontMatter.title || baseID;
@ -114,8 +119,9 @@ export default async function processMetadata({
// The last portion of the url path. Eg: 'foo/bar', 'bar'.
const routePath =
version && version !== 'next'
? id.replace(new RegExp(`^version-${version}/`), '')
: id;
? slug.replace(new RegExp(`^version-${version}/`), '')
: slug;
const permalink = normalizeUrl([
baseUrl,
routeBasePath,

View file

@ -20,7 +20,7 @@ website # Root directory of your site
└── hello.md
```
However, the last part of the `id` can be defined by user in the front matter. For example, if `guide/hello.md`'s content is defined as below, its final `id` is `guide/part1`.
However, the **last part** of the `id` can be defined by user in the front matter. For example, if `guide/hello.md`'s content is defined as below, its final `id` is `guide/part1`.
```yml
---
@ -29,6 +29,16 @@ id: part1
Lorem ipsum
```
If you want more control over the last part of the document URL, it is possible to add a `slug` (defaults to the `id`).
```yml
---
id: part1
slug: part1.html
---
Lorem ipsum
```
## Home page docs
Using the `homePageId` property, you can create a home page of your docs. To do this, you can create a new document, especially for this purpose with the id as `_index`, or you could specify an existing document id.