From b8de9c6dedceaef2a769b6ec3c24d9464ade0106 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Lorber?= Date: Tue, 2 Jun 2020 19:50:30 +0200 Subject: [PATCH] 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 Co-authored-by: Alexey Pyltsyn --- .../docs/invalid-id.md | 0 .../bad-slug-site/docs/invalid-slug.md | 5 ++++ .../__fixtures__/simple-site/docs/foo/baz.md | 1 + .../versioned-site/docs/foo/bar.md | 3 +++ .../versioned_docs/version-1.0.0/foo/bar.md | 3 +++ .../__snapshots__/index.test.ts.snap | 20 +++++++------- .../src/__tests__/index.test.ts | 10 +++---- .../src/__tests__/metadata.test.ts | 27 ++++++++++++++++--- .../src/metadata.ts | 14 +++++++--- website/docs/docs.md | 12 ++++++++- 10 files changed, 71 insertions(+), 24 deletions(-) rename packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/{bad-site => bad-id-site}/docs/invalid-id.md (100%) create mode 100644 packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/bad-slug-site/docs/invalid-slug.md diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/bad-site/docs/invalid-id.md b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/bad-id-site/docs/invalid-id.md similarity index 100% rename from packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/bad-site/docs/invalid-id.md rename to packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/bad-id-site/docs/invalid-id.md diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/bad-slug-site/docs/invalid-slug.md b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/bad-slug-site/docs/invalid-slug.md new file mode 100644 index 0000000000..18a5c857f2 --- /dev/null +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/bad-slug-site/docs/invalid-slug.md @@ -0,0 +1,5 @@ +--- +slug: hello/super +--- + +Lorem diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/docs/foo/baz.md b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/docs/foo/baz.md index bc29b950dc..672ae0f503 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/docs/foo/baz.md +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/docs/foo/baz.md @@ -1,6 +1,7 @@ --- id: baz title: baz +slug: bazSlug.html --- ## Images diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/versioned-site/docs/foo/bar.md b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/versioned-site/docs/foo/bar.md index 5a50106012..2ad77f287c 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/versioned-site/docs/foo/bar.md +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/versioned-site/docs/foo/bar.md @@ -1 +1,4 @@ +--- +slug: barSlug +--- This is `next` version of bar. diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/versioned-site/versioned_docs/version-1.0.0/foo/bar.md b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/versioned-site/versioned_docs/version-1.0.0/foo/bar.md index 8ac9246391..05f0d80763 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/versioned-site/versioned_docs/version-1.0.0/foo/bar.md +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/versioned-site/versioned_docs/version-1.0.0/foo/bar.md @@ -1 +1,4 @@ +--- +slug: barSlug +--- Bar `1.0.0` ! diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap index 9c2e00cd32..10b5e10336 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap @@ -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", diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts index 919c1afd2b..5805b07990 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts @@ -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', }, }); diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/metadata.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/metadata.test.ts index aeff67339a..3f413199b8 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/metadata.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/metadata.test.ts @@ -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 !', diff --git a/packages/docusaurus-plugin-content-docs/src/metadata.ts b/packages/docusaurus-plugin-content-docs/src/metadata.ts index 6dfd498243..4a44ca1209 100644 --- a/packages/docusaurus-plugin-content-docs/src/metadata.ts +++ b/packages/docusaurus-plugin-content-docs/src/metadata.ts @@ -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, diff --git a/website/docs/docs.md b/website/docs/docs.md index 1f4546555f..192a91f712 100644 --- a/website/docs/docs.md +++ b/website/docs/docs.md @@ -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.