mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-10 07:37:19 +02:00
feat(v2): absolute slugs and slug resolution system (#3084)
* rework slug to allow absolute slugs and slug resolution * add slug metadata tests * refactor docs metadata test + fix slug bugs * fix tests * fix docs tests failing due to randomness + update snapshot * add test for addLeadingSlash
This commit is contained in:
parent
6730590c1e
commit
f4434b2e42
39 changed files with 791 additions and 255 deletions
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
slug: hello/super
|
||||
---
|
||||
|
||||
Lorem
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
slug: /rootAbsoluteSlug
|
||||
---
|
||||
|
||||
Lorem
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
slug: rootRelativeSlug
|
||||
---
|
||||
|
||||
Lorem
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
slug: ./hey/ho/../rootResolvedSlug
|
||||
---
|
||||
|
||||
Lorem
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
slug: ../../../../../../../../rootTryToEscapeSlug
|
||||
---
|
||||
|
||||
Lorem
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
slug: /absoluteSlug
|
||||
---
|
||||
|
||||
Lorem
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
slug: relativeSlug
|
||||
---
|
||||
|
||||
Lorem
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
slug: ./hey/ho/../resolvedSlug
|
||||
---
|
||||
|
||||
Lorem
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
slug: ../../../../../../../../tryToEscapeSlug
|
||||
---
|
||||
|
||||
Lorem
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
slug: /absoluteSlug
|
||||
---
|
||||
|
||||
Lorem
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
slug: relativeSlug
|
||||
---
|
||||
|
||||
Lorem
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
slug: ./hey/ho/../resolvedSlug
|
||||
---
|
||||
|
||||
Lorem
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
slug: ../../../../../../../../tryToEscapeSlug
|
||||
---
|
||||
|
||||
Lorem
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
slug: /rootAbsoluteSlug
|
||||
---
|
||||
|
||||
Lorem
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
slug: rootRelativeSlug
|
||||
---
|
||||
|
||||
Lorem
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
slug: ./hey/ho/../rootResolvedSlug
|
||||
---
|
||||
|
||||
Lorem
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
slug: ../../../../../../../../rootTryToEscapeSlug
|
||||
---
|
||||
|
||||
Lorem
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
slug: /absoluteSlug
|
||||
---
|
||||
|
||||
Lorem
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
slug: relativeSlug
|
||||
---
|
||||
|
||||
Lorem
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
slug: ./hey/ho/../resolvedSlug
|
||||
---
|
||||
|
||||
Lorem
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
slug: ../../../../../../../../tryToEscapeSlug
|
||||
---
|
||||
|
||||
Lorem
|
|
@ -1,4 +1,5 @@
|
|||
[
|
||||
"1.0.1",
|
||||
"1.0.0"
|
||||
"1.0.0",
|
||||
"withSlugs"
|
||||
]
|
||||
|
|
|
@ -72,6 +72,14 @@ Array [
|
|||
},
|
||||
"path": "/docs/",
|
||||
},
|
||||
Object {
|
||||
"component": "@theme/DocItem",
|
||||
"exact": true,
|
||||
"modules": Object {
|
||||
"content": "@site/docs/slugs/absoluteSlug.md",
|
||||
},
|
||||
"path": "/docs/absoluteSlug",
|
||||
},
|
||||
Object {
|
||||
"component": "@theme/DocItem",
|
||||
"exact": true,
|
||||
|
@ -88,6 +96,14 @@ Array [
|
|||
},
|
||||
"path": "/docs/foo/bazSlug.html",
|
||||
},
|
||||
Object {
|
||||
"component": "@theme/DocItem",
|
||||
"exact": true,
|
||||
"modules": Object {
|
||||
"content": "@site/docs/rootResolvedSlug.md",
|
||||
},
|
||||
"path": "/docs/hey/rootResolvedSlug",
|
||||
},
|
||||
Object {
|
||||
"component": "@theme/DocItem",
|
||||
"exact": true,
|
||||
|
@ -104,6 +120,54 @@ Array [
|
|||
},
|
||||
"path": "/docs/lorem",
|
||||
},
|
||||
Object {
|
||||
"component": "@theme/DocItem",
|
||||
"exact": true,
|
||||
"modules": Object {
|
||||
"content": "@site/docs/rootAbsoluteSlug.md",
|
||||
},
|
||||
"path": "/docs/rootAbsoluteSlug",
|
||||
},
|
||||
Object {
|
||||
"component": "@theme/DocItem",
|
||||
"exact": true,
|
||||
"modules": Object {
|
||||
"content": "@site/docs/rootRelativeSlug.md",
|
||||
},
|
||||
"path": "/docs/rootRelativeSlug",
|
||||
},
|
||||
Object {
|
||||
"component": "@theme/DocItem",
|
||||
"exact": true,
|
||||
"modules": Object {
|
||||
"content": "@site/docs/rootTryToEscapeSlug.md",
|
||||
},
|
||||
"path": "/docs/rootTryToEscapeSlug",
|
||||
},
|
||||
Object {
|
||||
"component": "@theme/DocItem",
|
||||
"exact": true,
|
||||
"modules": Object {
|
||||
"content": "@site/docs/slugs/resolvedSlug.md",
|
||||
},
|
||||
"path": "/docs/slugs/hey/resolvedSlug",
|
||||
},
|
||||
Object {
|
||||
"component": "@theme/DocItem",
|
||||
"exact": true,
|
||||
"modules": Object {
|
||||
"content": "@site/docs/slugs/relativeSlug.md",
|
||||
},
|
||||
"path": "/docs/slugs/relativeSlug",
|
||||
},
|
||||
Object {
|
||||
"component": "@theme/DocItem",
|
||||
"exact": true,
|
||||
"modules": Object {
|
||||
"content": "@site/docs/slugs/tryToEscapeSlug.md",
|
||||
},
|
||||
"path": "/docs/tryToEscapeSlug",
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
@ -138,6 +202,38 @@ Object {
|
|||
"id": "lorem",
|
||||
"path": "/docs/lorem",
|
||||
},
|
||||
Object {
|
||||
"id": "rootAbsoluteSlug",
|
||||
"path": "/docs/rootAbsoluteSlug",
|
||||
},
|
||||
Object {
|
||||
"id": "rootRelativeSlug",
|
||||
"path": "/docs/rootRelativeSlug",
|
||||
},
|
||||
Object {
|
||||
"id": "rootResolvedSlug",
|
||||
"path": "/docs/hey/rootResolvedSlug",
|
||||
},
|
||||
Object {
|
||||
"id": "rootTryToEscapeSlug",
|
||||
"path": "/docs/rootTryToEscapeSlug",
|
||||
},
|
||||
Object {
|
||||
"id": "slugs/absoluteSlug",
|
||||
"path": "/docs/absoluteSlug",
|
||||
},
|
||||
Object {
|
||||
"id": "slugs/relativeSlug",
|
||||
"path": "/docs/slugs/relativeSlug",
|
||||
},
|
||||
Object {
|
||||
"id": "slugs/resolvedSlug",
|
||||
"path": "/docs/slugs/hey/resolvedSlug",
|
||||
},
|
||||
Object {
|
||||
"id": "slugs/tryToEscapeSlug",
|
||||
"path": "/docs/tryToEscapeSlug",
|
||||
},
|
||||
],
|
||||
"mainDocId": "hello",
|
||||
"name": null,
|
||||
|
@ -156,7 +252,15 @@ Available document ids=
|
|||
- foo/baz
|
||||
- hello
|
||||
- ipsum
|
||||
- lorem"
|
||||
- lorem
|
||||
- rootAbsoluteSlug
|
||||
- rootRelativeSlug
|
||||
- rootResolvedSlug
|
||||
- rootTryToEscapeSlug
|
||||
- slugs/absoluteSlug
|
||||
- slugs/relativeSlug
|
||||
- slugs/resolvedSlug
|
||||
- slugs/tryToEscapeSlug"
|
||||
`;
|
||||
|
||||
exports[`versioned website content 1`] = `
|
||||
|
@ -213,6 +317,14 @@ Array [
|
|||
},
|
||||
"path": "/docs/next/",
|
||||
},
|
||||
Object {
|
||||
"component": "@theme/DocItem",
|
||||
"exact": true,
|
||||
"modules": Object {
|
||||
"content": "@site/docs/slugs/absoluteSlug.md",
|
||||
},
|
||||
"path": "/docs/next/absoluteSlug",
|
||||
},
|
||||
Object {
|
||||
"component": "@theme/DocItem",
|
||||
"exact": true,
|
||||
|
@ -221,6 +333,105 @@ Array [
|
|||
},
|
||||
"path": "/docs/next/foo/barSlug",
|
||||
},
|
||||
Object {
|
||||
"component": "@theme/DocItem",
|
||||
"exact": true,
|
||||
"modules": Object {
|
||||
"content": "@site/docs/slugs/resolvedSlug.md",
|
||||
},
|
||||
"path": "/docs/next/slugs/hey/resolvedSlug",
|
||||
},
|
||||
Object {
|
||||
"component": "@theme/DocItem",
|
||||
"exact": true,
|
||||
"modules": Object {
|
||||
"content": "@site/docs/slugs/relativeSlug.md",
|
||||
},
|
||||
"path": "/docs/next/slugs/relativeSlug",
|
||||
},
|
||||
Object {
|
||||
"component": "@theme/DocItem",
|
||||
"exact": true,
|
||||
"modules": Object {
|
||||
"content": "@site/docs/slugs/tryToEscapeSlug.md",
|
||||
},
|
||||
"path": "/docs/next/tryToEscapeSlug",
|
||||
},
|
||||
],
|
||||
},
|
||||
Object {
|
||||
"component": "@theme/DocPage",
|
||||
"exact": false,
|
||||
"modules": Object {
|
||||
"docsMetadata": "~docs/docs-with-slugs-route-335.json",
|
||||
},
|
||||
"path": "/docs/withSlugs",
|
||||
"priority": undefined,
|
||||
"routes": Array [
|
||||
Object {
|
||||
"component": "@theme/DocItem",
|
||||
"exact": true,
|
||||
"modules": Object {
|
||||
"content": "@site/versioned_docs/version-withSlugs/slugs/absoluteSlug.md",
|
||||
},
|
||||
"path": "/docs/withSlugs/absoluteSlug",
|
||||
},
|
||||
Object {
|
||||
"component": "@theme/DocItem",
|
||||
"exact": true,
|
||||
"modules": Object {
|
||||
"content": "@site/versioned_docs/version-withSlugs/rootResolvedSlug.md",
|
||||
},
|
||||
"path": "/docs/withSlugs/hey/rootResolvedSlug",
|
||||
},
|
||||
Object {
|
||||
"component": "@theme/DocItem",
|
||||
"exact": true,
|
||||
"modules": Object {
|
||||
"content": "@site/versioned_docs/version-withSlugs/rootAbsoluteSlug.md",
|
||||
},
|
||||
"path": "/docs/withSlugs/rootAbsoluteSlug",
|
||||
},
|
||||
Object {
|
||||
"component": "@theme/DocItem",
|
||||
"exact": true,
|
||||
"modules": Object {
|
||||
"content": "@site/versioned_docs/version-withSlugs/rootRelativeSlug.md",
|
||||
},
|
||||
"path": "/docs/withSlugs/rootRelativeSlug",
|
||||
},
|
||||
Object {
|
||||
"component": "@theme/DocItem",
|
||||
"exact": true,
|
||||
"modules": Object {
|
||||
"content": "@site/versioned_docs/version-withSlugs/rootTryToEscapeSlug.md",
|
||||
},
|
||||
"path": "/docs/withSlugs/rootTryToEscapeSlug",
|
||||
},
|
||||
Object {
|
||||
"component": "@theme/DocItem",
|
||||
"exact": true,
|
||||
"modules": Object {
|
||||
"content": "@site/versioned_docs/version-withSlugs/slugs/resolvedSlug.md",
|
||||
},
|
||||
"path": "/docs/withSlugs/slugs/hey/resolvedSlug",
|
||||
},
|
||||
Object {
|
||||
"component": "@theme/DocItem",
|
||||
"exact": true,
|
||||
"modules": Object {
|
||||
"content": "@site/versioned_docs/version-withSlugs/slugs/relativeSlug.md",
|
||||
},
|
||||
"path": "/docs/withSlugs/slugs/relativeSlug",
|
||||
},
|
||||
Object {
|
||||
"component": "@theme/DocItem",
|
||||
"exact": true,
|
||||
"modules": Object {
|
||||
"content": "@site/versioned_docs/version-withSlugs/slugs/tryToEscapeSlug.md",
|
||||
},
|
||||
"path": "/docs/withSlugs/tryToEscapeSlug",
|
||||
},
|
||||
],
|
||||
},
|
||||
Object {
|
||||
|
@ -270,6 +481,22 @@ Object {
|
|||
"id": "hello",
|
||||
"path": "/docs/next/",
|
||||
},
|
||||
Object {
|
||||
"id": "slugs/absoluteSlug",
|
||||
"path": "/docs/next/absoluteSlug",
|
||||
},
|
||||
Object {
|
||||
"id": "slugs/relativeSlug",
|
||||
"path": "/docs/next/slugs/relativeSlug",
|
||||
},
|
||||
Object {
|
||||
"id": "slugs/resolvedSlug",
|
||||
"path": "/docs/next/slugs/hey/resolvedSlug",
|
||||
},
|
||||
Object {
|
||||
"id": "slugs/tryToEscapeSlug",
|
||||
"path": "/docs/next/tryToEscapeSlug",
|
||||
},
|
||||
],
|
||||
"mainDocId": "hello",
|
||||
"name": "next",
|
||||
|
@ -309,6 +536,45 @@ Object {
|
|||
"name": "1.0.0",
|
||||
"path": "/docs/1.0.0",
|
||||
},
|
||||
Object {
|
||||
"docs": Array [
|
||||
Object {
|
||||
"id": "rootAbsoluteSlug",
|
||||
"path": "/docs/withSlugs/rootAbsoluteSlug",
|
||||
},
|
||||
Object {
|
||||
"id": "rootRelativeSlug",
|
||||
"path": "/docs/withSlugs/rootRelativeSlug",
|
||||
},
|
||||
Object {
|
||||
"id": "rootResolvedSlug",
|
||||
"path": "/docs/withSlugs/hey/rootResolvedSlug",
|
||||
},
|
||||
Object {
|
||||
"id": "rootTryToEscapeSlug",
|
||||
"path": "/docs/withSlugs/rootTryToEscapeSlug",
|
||||
},
|
||||
Object {
|
||||
"id": "slugs/absoluteSlug",
|
||||
"path": "/docs/withSlugs/absoluteSlug",
|
||||
},
|
||||
Object {
|
||||
"id": "slugs/relativeSlug",
|
||||
"path": "/docs/withSlugs/slugs/relativeSlug",
|
||||
},
|
||||
Object {
|
||||
"id": "slugs/resolvedSlug",
|
||||
"path": "/docs/withSlugs/slugs/hey/resolvedSlug",
|
||||
},
|
||||
Object {
|
||||
"id": "slugs/tryToEscapeSlug",
|
||||
"path": "/docs/withSlugs/tryToEscapeSlug",
|
||||
},
|
||||
],
|
||||
"mainDocId": "rootAbsoluteSlug",
|
||||
"name": "withSlugs",
|
||||
"path": "/docs/withSlugs",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
|
|
|
@ -21,7 +21,11 @@ describe('loadEnv', () => {
|
|||
const env = loadEnv(siteDir);
|
||||
expect(env.versioning.enabled).toBe(true);
|
||||
expect(env.versioning.latestVersion).toBe('1.0.1');
|
||||
expect(env.versioning.versions).toStrictEqual(['1.0.1', '1.0.0']);
|
||||
expect(env.versioning.versions).toStrictEqual([
|
||||
'1.0.1',
|
||||
'1.0.0',
|
||||
'withSlugs',
|
||||
]);
|
||||
});
|
||||
|
||||
test('website with versioning but disabled', () => {
|
||||
|
|
|
@ -269,8 +269,10 @@ describe('versioned website', () => {
|
|||
"docs/**/*.{md,mdx}",
|
||||
"versioned_sidebars/version-1.0.1-sidebars.json",
|
||||
"versioned_sidebars/version-1.0.0-sidebars.json",
|
||||
"versioned_sidebars/version-withSlugs-sidebars.json",
|
||||
"versioned_docs/version-1.0.1/**/*.{md,mdx}",
|
||||
"versioned_docs/version-1.0.0/**/*.{md,mdx}",
|
||||
"versioned_docs/version-withSlugs/**/*.{md,mdx}",
|
||||
"sidebars.json",
|
||||
]
|
||||
`);
|
||||
|
|
|
@ -9,136 +9,150 @@ import path from 'path';
|
|||
import {loadContext} from '@docusaurus/core/src/server/index';
|
||||
import processMetadata from '../metadata';
|
||||
import loadEnv from '../env';
|
||||
import {MetadataRaw, Env, MetadataOptions} from '../types';
|
||||
import {LoadContext} from '@docusaurus/types';
|
||||
|
||||
const fixtureDir = path.join(__dirname, '__fixtures__');
|
||||
|
||||
describe('simple site', () => {
|
||||
const simpleSiteDir = path.join(fixtureDir, 'simple-site');
|
||||
const context = loadContext(simpleSiteDir);
|
||||
const routeBasePath = 'docs';
|
||||
const docsDir = path.resolve(simpleSiteDir, routeBasePath);
|
||||
function createTestHelpers({
|
||||
siteDir,
|
||||
context,
|
||||
env,
|
||||
options,
|
||||
}: {
|
||||
siteDir: string;
|
||||
context: LoadContext;
|
||||
env: Env;
|
||||
options: MetadataOptions;
|
||||
}) {
|
||||
async function testMeta(
|
||||
refDir: string,
|
||||
source: string,
|
||||
expectedMetadata: Omit<MetadataRaw, 'source'>,
|
||||
) {
|
||||
const metadata = await processMetadata({
|
||||
source,
|
||||
refDir,
|
||||
context,
|
||||
options,
|
||||
env,
|
||||
});
|
||||
expect(metadata).toEqual({
|
||||
...expectedMetadata,
|
||||
source: path.join('@site', path.relative(siteDir, refDir), source),
|
||||
});
|
||||
}
|
||||
|
||||
const env = loadEnv(simpleSiteDir);
|
||||
async function testSlug(
|
||||
refDir: string,
|
||||
source: string,
|
||||
expectedPermalink: string,
|
||||
) {
|
||||
const metadata = await processMetadata({
|
||||
source,
|
||||
refDir,
|
||||
context,
|
||||
options,
|
||||
env,
|
||||
});
|
||||
expect(metadata.permalink).toEqual(expectedPermalink);
|
||||
}
|
||||
|
||||
return {testMeta, testSlug};
|
||||
}
|
||||
|
||||
describe('simple site', () => {
|
||||
const siteDir = path.join(fixtureDir, 'simple-site');
|
||||
const context = loadContext(siteDir);
|
||||
const routeBasePath = 'docs';
|
||||
const docsDir = path.resolve(siteDir, routeBasePath);
|
||||
const env = loadEnv(siteDir);
|
||||
const options = {routeBasePath};
|
||||
|
||||
const {testMeta, testSlug} = createTestHelpers({
|
||||
siteDir,
|
||||
context,
|
||||
options,
|
||||
env,
|
||||
});
|
||||
|
||||
test('normal docs', async () => {
|
||||
const sourceA = path.join('foo', 'bar.md');
|
||||
const sourceB = path.join('hello.md');
|
||||
const options = {
|
||||
routeBasePath,
|
||||
};
|
||||
|
||||
const [dataA, dataB] = await Promise.all([
|
||||
processMetadata({
|
||||
source: sourceA,
|
||||
refDir: docsDir,
|
||||
context,
|
||||
options,
|
||||
env,
|
||||
}),
|
||||
processMetadata({
|
||||
source: sourceB,
|
||||
refDir: docsDir,
|
||||
context,
|
||||
options,
|
||||
env,
|
||||
}),
|
||||
]);
|
||||
|
||||
expect(dataA).toEqual({
|
||||
await testMeta(docsDir, path.join('foo', 'bar.md'), {
|
||||
id: 'foo/bar',
|
||||
unversionedId: 'foo/bar',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/foo/bar',
|
||||
source: path.join('@site', routeBasePath, sourceA),
|
||||
title: 'Bar',
|
||||
description: 'This is custom description',
|
||||
});
|
||||
expect(dataB).toEqual({
|
||||
await testMeta(docsDir, path.join('hello.md'), {
|
||||
id: 'hello',
|
||||
unversionedId: 'hello',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/hello',
|
||||
source: path.join('@site', routeBasePath, sourceB),
|
||||
title: 'Hello, World !',
|
||||
description: `Hi, Endilie here :)`,
|
||||
});
|
||||
});
|
||||
|
||||
test('homePageId doc', async () => {
|
||||
const source = path.join('hello.md');
|
||||
const options = {
|
||||
routeBasePath,
|
||||
homePageId: 'hello',
|
||||
};
|
||||
|
||||
const data = await processMetadata({
|
||||
source,
|
||||
refDir: docsDir,
|
||||
const {testMeta: testMetaLocal} = createTestHelpers({
|
||||
siteDir,
|
||||
options: {
|
||||
routeBasePath,
|
||||
homePageId: 'hello',
|
||||
},
|
||||
context,
|
||||
options,
|
||||
env,
|
||||
});
|
||||
|
||||
expect(data).toEqual({
|
||||
await testMetaLocal(docsDir, path.join('hello.md'), {
|
||||
id: 'hello',
|
||||
unversionedId: 'hello',
|
||||
isDocsHomePage: true,
|
||||
permalink: '/docs/',
|
||||
source: path.join('@site', routeBasePath, source),
|
||||
title: 'Hello, World !',
|
||||
description: `Hi, Endilie here :)`,
|
||||
});
|
||||
});
|
||||
|
||||
test('homePageId doc nested', async () => {
|
||||
const source = path.join('foo', 'bar.md');
|
||||
const options = {
|
||||
routeBasePath,
|
||||
homePageId: 'foo/bar',
|
||||
};
|
||||
|
||||
const data = await processMetadata({
|
||||
source,
|
||||
refDir: docsDir,
|
||||
const {testMeta: testMetaLocal} = createTestHelpers({
|
||||
siteDir,
|
||||
options: {
|
||||
routeBasePath,
|
||||
homePageId: 'foo/bar',
|
||||
},
|
||||
context,
|
||||
options,
|
||||
env,
|
||||
});
|
||||
|
||||
expect(data).toEqual({
|
||||
await testMetaLocal(docsDir, path.join('foo', 'bar.md'), {
|
||||
id: 'foo/bar',
|
||||
unversionedId: 'foo/bar',
|
||||
isDocsHomePage: true,
|
||||
permalink: '/docs/',
|
||||
source: path.join('@site', routeBasePath, source),
|
||||
title: 'Bar',
|
||||
description: 'This is custom description',
|
||||
});
|
||||
});
|
||||
|
||||
test('docs with editUrl', async () => {
|
||||
const editUrl =
|
||||
'https://github.com/facebook/docusaurus/edit/master/website';
|
||||
const source = path.join('foo', 'baz.md');
|
||||
const options = {
|
||||
routeBasePath,
|
||||
editUrl,
|
||||
};
|
||||
|
||||
const data = await processMetadata({
|
||||
source,
|
||||
refDir: docsDir,
|
||||
const {testMeta: testMetaLocal} = createTestHelpers({
|
||||
siteDir,
|
||||
options: {
|
||||
routeBasePath,
|
||||
editUrl: 'https://github.com/facebook/docusaurus/edit/master/website',
|
||||
},
|
||||
context,
|
||||
options,
|
||||
env,
|
||||
});
|
||||
|
||||
expect(data).toEqual({
|
||||
await testMetaLocal(docsDir, path.join('foo', 'baz.md'), {
|
||||
id: 'foo/baz',
|
||||
unversionedId: 'foo/baz',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/foo/bazSlug.html',
|
||||
source: path.join('@site', routeBasePath, source),
|
||||
title: 'baz',
|
||||
editUrl:
|
||||
'https://github.com/facebook/docusaurus/edit/master/website/docs/foo/baz.md',
|
||||
|
@ -147,57 +161,34 @@ describe('simple site', () => {
|
|||
});
|
||||
|
||||
test('docs with custom editUrl & unrelated frontmatter', async () => {
|
||||
const source = 'lorem.md';
|
||||
const options = {
|
||||
routeBasePath,
|
||||
};
|
||||
|
||||
const data = await processMetadata({
|
||||
source,
|
||||
refDir: docsDir,
|
||||
context,
|
||||
options,
|
||||
env,
|
||||
});
|
||||
|
||||
expect(data).toEqual({
|
||||
await testMeta(docsDir, 'lorem.md', {
|
||||
id: 'lorem',
|
||||
unversionedId: 'lorem',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/lorem',
|
||||
source: path.join('@site', routeBasePath, source),
|
||||
title: 'lorem',
|
||||
editUrl: 'https://github.com/customUrl/docs/lorem.md',
|
||||
description: 'Lorem ipsum.',
|
||||
});
|
||||
|
||||
// unrelated frontmatter is not part of metadata
|
||||
// @ts-expect-error: It doesn't exist, so the test will show it's undefined.
|
||||
expect(data.unrelated_frontmatter).toBeUndefined();
|
||||
});
|
||||
|
||||
test('docs with last update time and author', async () => {
|
||||
const source = 'lorem.md';
|
||||
const options = {
|
||||
routeBasePath,
|
||||
showLastUpdateAuthor: true,
|
||||
showLastUpdateTime: true,
|
||||
};
|
||||
|
||||
const data = await processMetadata({
|
||||
source,
|
||||
refDir: docsDir,
|
||||
const {testMeta: testMetaLocal} = createTestHelpers({
|
||||
siteDir,
|
||||
options: {
|
||||
routeBasePath,
|
||||
showLastUpdateAuthor: true,
|
||||
showLastUpdateTime: true,
|
||||
},
|
||||
context,
|
||||
options,
|
||||
env,
|
||||
});
|
||||
|
||||
expect(data).toEqual({
|
||||
await testMetaLocal(docsDir, 'lorem.md', {
|
||||
id: 'lorem',
|
||||
unversionedId: 'lorem',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/lorem',
|
||||
source: path.join('@site', routeBasePath, source),
|
||||
title: 'lorem',
|
||||
editUrl: 'https://github.com/customUrl/docs/lorem.md',
|
||||
description: 'Lorem ipsum.',
|
||||
|
@ -207,27 +198,22 @@ describe('simple site', () => {
|
|||
});
|
||||
|
||||
test('docs with null custom_edit_url', async () => {
|
||||
const source = 'ipsum.md';
|
||||
const options = {
|
||||
routeBasePath,
|
||||
showLastUpdateAuthor: true,
|
||||
showLastUpdateTime: true,
|
||||
};
|
||||
|
||||
const data = await processMetadata({
|
||||
source,
|
||||
refDir: docsDir,
|
||||
const {testMeta: testMetaLocal} = createTestHelpers({
|
||||
siteDir,
|
||||
options: {
|
||||
routeBasePath,
|
||||
showLastUpdateAuthor: true,
|
||||
showLastUpdateTime: true,
|
||||
},
|
||||
context,
|
||||
options,
|
||||
env,
|
||||
});
|
||||
|
||||
expect(data).toEqual({
|
||||
await testMetaLocal(docsDir, 'ipsum.md', {
|
||||
id: 'ipsum',
|
||||
unversionedId: 'ipsum',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/ipsum',
|
||||
source: path.join('@site', routeBasePath, source),
|
||||
title: 'ipsum',
|
||||
editUrl: null,
|
||||
description: 'Lorem ipsum.',
|
||||
|
@ -236,18 +222,61 @@ describe('simple site', () => {
|
|||
});
|
||||
});
|
||||
|
||||
test('docs with slugs', async () => {
|
||||
await testSlug(
|
||||
docsDir,
|
||||
path.join('rootRelativeSlug.md'),
|
||||
'/docs/rootRelativeSlug',
|
||||
);
|
||||
await testSlug(
|
||||
docsDir,
|
||||
path.join('rootAbsoluteSlug.md'),
|
||||
'/docs/rootAbsoluteSlug',
|
||||
);
|
||||
await testSlug(
|
||||
docsDir,
|
||||
path.join('rootResolvedSlug.md'),
|
||||
'/docs/hey/rootResolvedSlug',
|
||||
);
|
||||
await testSlug(
|
||||
docsDir,
|
||||
path.join('rootTryToEscapeSlug.md'),
|
||||
'/docs/rootTryToEscapeSlug',
|
||||
);
|
||||
|
||||
await testSlug(
|
||||
docsDir,
|
||||
path.join('slugs', 'absoluteSlug.md'),
|
||||
'/docs/absoluteSlug',
|
||||
);
|
||||
await testSlug(
|
||||
docsDir,
|
||||
path.join('slugs', 'relativeSlug.md'),
|
||||
'/docs/slugs/relativeSlug',
|
||||
);
|
||||
await testSlug(
|
||||
docsDir,
|
||||
path.join('slugs', 'resolvedSlug.md'),
|
||||
'/docs/slugs/hey/resolvedSlug',
|
||||
);
|
||||
await testSlug(
|
||||
docsDir,
|
||||
path.join('slugs', 'tryToEscapeSlug.md'),
|
||||
'/docs/tryToEscapeSlug',
|
||||
);
|
||||
});
|
||||
|
||||
test('docs with invalid id', async () => {
|
||||
const badSiteDir = path.join(fixtureDir, 'bad-id-site');
|
||||
const options = {
|
||||
routeBasePath,
|
||||
};
|
||||
|
||||
await expect(
|
||||
processMetadata({
|
||||
source: 'invalid-id.md',
|
||||
refDir: path.join(badSiteDir, 'docs'),
|
||||
context,
|
||||
options,
|
||||
options: {
|
||||
routeBasePath,
|
||||
},
|
||||
env,
|
||||
}),
|
||||
).rejects.toThrowErrorMatchingInlineSnapshot(
|
||||
|
@ -255,38 +284,18 @@ describe('simple site', () => {
|
|||
);
|
||||
});
|
||||
|
||||
test('docs with invalid slug', async () => {
|
||||
const badSiteDir = path.join(fixtureDir, 'bad-slug-site');
|
||||
const options = {
|
||||
routeBasePath,
|
||||
};
|
||||
|
||||
await expect(
|
||||
processMetadata({
|
||||
source: 'invalid-slug.md',
|
||||
refDir: path.join(badSiteDir, 'docs'),
|
||||
context,
|
||||
options,
|
||||
env,
|
||||
}),
|
||||
).rejects.toThrowErrorMatchingInlineSnapshot(
|
||||
`"Document slug cannot include \\"/\\"."`,
|
||||
);
|
||||
});
|
||||
|
||||
test('docs with slug on doc home', async () => {
|
||||
const badSiteDir = path.join(fixtureDir, 'bad-slug-on-doc-home-site');
|
||||
const options = {
|
||||
routeBasePath,
|
||||
homePageId: 'docWithSlug',
|
||||
};
|
||||
|
||||
await expect(
|
||||
processMetadata({
|
||||
source: 'docWithSlug.md',
|
||||
refDir: path.join(badSiteDir, 'docs'),
|
||||
context,
|
||||
options,
|
||||
options: {
|
||||
routeBasePath,
|
||||
homePageId: 'docWithSlug',
|
||||
},
|
||||
env,
|
||||
}),
|
||||
).rejects.toThrowErrorMatchingInlineSnapshot(
|
||||
|
@ -302,47 +311,30 @@ describe('versioned site', () => {
|
|||
const docsDir = path.resolve(siteDir, routeBasePath);
|
||||
const env = loadEnv(siteDir);
|
||||
const {docsDir: versionedDir} = env.versioning;
|
||||
const options = {routeBasePath};
|
||||
|
||||
test('master/next docs', async () => {
|
||||
const sourceA = path.join('foo', 'bar.md');
|
||||
const sourceB = path.join('hello.md');
|
||||
const options = {
|
||||
routeBasePath,
|
||||
};
|
||||
const {testMeta, testSlug} = createTestHelpers({
|
||||
siteDir,
|
||||
context,
|
||||
options,
|
||||
env,
|
||||
});
|
||||
|
||||
const [dataA, dataB] = await Promise.all([
|
||||
processMetadata({
|
||||
source: sourceA,
|
||||
refDir: docsDir,
|
||||
context,
|
||||
options,
|
||||
env,
|
||||
}),
|
||||
processMetadata({
|
||||
source: sourceB,
|
||||
refDir: docsDir,
|
||||
context,
|
||||
options,
|
||||
env,
|
||||
}),
|
||||
]);
|
||||
|
||||
expect(dataA).toEqual({
|
||||
test('next docs', async () => {
|
||||
await testMeta(docsDir, path.join('foo', 'bar.md'), {
|
||||
id: 'foo/bar',
|
||||
unversionedId: 'foo/bar',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/next/foo/barSlug',
|
||||
source: path.join('@site', routeBasePath, sourceA),
|
||||
title: 'bar',
|
||||
description: 'This is next version of bar.',
|
||||
version: 'next',
|
||||
});
|
||||
expect(dataB).toEqual({
|
||||
await testMeta(docsDir, path.join('hello.md'), {
|
||||
id: 'hello',
|
||||
unversionedId: 'hello',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/next/hello',
|
||||
source: path.join('@site', routeBasePath, sourceB),
|
||||
title: 'hello',
|
||||
description: 'Hello next !',
|
||||
version: 'next',
|
||||
|
@ -350,84 +342,108 @@ describe('versioned site', () => {
|
|||
});
|
||||
|
||||
test('versioned docs', async () => {
|
||||
const sourceA = path.join('version-1.0.0', 'foo', 'bar.md');
|
||||
const sourceB = path.join('version-1.0.0', 'hello.md');
|
||||
const sourceC = path.join('version-1.0.1', 'foo', 'bar.md');
|
||||
const sourceD = path.join('version-1.0.1', 'hello.md');
|
||||
const options = {
|
||||
routeBasePath,
|
||||
};
|
||||
|
||||
const [dataA, dataB, dataC, dataD] = await Promise.all([
|
||||
processMetadata({
|
||||
source: sourceA,
|
||||
refDir: versionedDir,
|
||||
context,
|
||||
options,
|
||||
env,
|
||||
}),
|
||||
processMetadata({
|
||||
source: sourceB,
|
||||
refDir: versionedDir,
|
||||
context,
|
||||
options,
|
||||
env,
|
||||
}),
|
||||
processMetadata({
|
||||
source: sourceC,
|
||||
refDir: versionedDir,
|
||||
context,
|
||||
options,
|
||||
env,
|
||||
}),
|
||||
processMetadata({
|
||||
source: sourceD,
|
||||
refDir: versionedDir,
|
||||
context,
|
||||
options,
|
||||
env,
|
||||
}),
|
||||
]);
|
||||
|
||||
expect(dataA).toEqual({
|
||||
await testMeta(versionedDir, path.join('version-1.0.0', 'foo', 'bar.md'), {
|
||||
id: 'version-1.0.0/foo/bar',
|
||||
unversionedId: 'foo/bar',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/1.0.0/foo/barSlug',
|
||||
source: path.join('@site', path.relative(siteDir, versionedDir), sourceA),
|
||||
title: 'bar',
|
||||
description: 'Bar 1.0.0 !',
|
||||
version: '1.0.0',
|
||||
});
|
||||
expect(dataB).toEqual({
|
||||
await testMeta(versionedDir, path.join('version-1.0.0', 'hello.md'), {
|
||||
id: 'version-1.0.0/hello',
|
||||
unversionedId: 'hello',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/1.0.0/hello',
|
||||
source: path.join('@site', path.relative(siteDir, versionedDir), sourceB),
|
||||
title: 'hello',
|
||||
description: 'Hello 1.0.0 !',
|
||||
version: '1.0.0',
|
||||
});
|
||||
expect(dataC).toEqual({
|
||||
await testMeta(versionedDir, path.join('version-1.0.1', 'foo', 'bar.md'), {
|
||||
id: 'version-1.0.1/foo/bar',
|
||||
unversionedId: 'foo/bar',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/foo/bar',
|
||||
source: path.join('@site', path.relative(siteDir, versionedDir), sourceC),
|
||||
title: 'bar',
|
||||
description: 'Bar 1.0.1 !',
|
||||
version: '1.0.1',
|
||||
});
|
||||
expect(dataD).toEqual({
|
||||
await testMeta(versionedDir, path.join('version-1.0.1', 'hello.md'), {
|
||||
id: 'version-1.0.1/hello',
|
||||
unversionedId: 'hello',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/hello',
|
||||
source: path.join('@site', path.relative(siteDir, versionedDir), sourceD),
|
||||
title: 'hello',
|
||||
description: 'Hello 1.0.1 !',
|
||||
version: '1.0.1',
|
||||
});
|
||||
});
|
||||
|
||||
test('next doc slugs', async () => {
|
||||
await testSlug(
|
||||
docsDir,
|
||||
path.join('slugs', 'absoluteSlug.md'),
|
||||
'/docs/next/absoluteSlug',
|
||||
);
|
||||
await testSlug(
|
||||
docsDir,
|
||||
path.join('slugs', 'relativeSlug.md'),
|
||||
'/docs/next/slugs/relativeSlug',
|
||||
);
|
||||
await testSlug(
|
||||
docsDir,
|
||||
path.join('slugs', 'resolvedSlug.md'),
|
||||
'/docs/next/slugs/hey/resolvedSlug',
|
||||
);
|
||||
await testSlug(
|
||||
docsDir,
|
||||
path.join('slugs', 'tryToEscapeSlug.md'),
|
||||
'/docs/next/tryToEscapeSlug',
|
||||
);
|
||||
});
|
||||
|
||||
test('versioned doc slugs', async () => {
|
||||
await testSlug(
|
||||
versionedDir,
|
||||
path.join('version-withSlugs', 'rootAbsoluteSlug.md'),
|
||||
'/docs/withSlugs/rootAbsoluteSlug',
|
||||
);
|
||||
await testSlug(
|
||||
versionedDir,
|
||||
path.join('version-withSlugs', 'rootRelativeSlug.md'),
|
||||
'/docs/withSlugs/rootRelativeSlug',
|
||||
);
|
||||
await testSlug(
|
||||
versionedDir,
|
||||
path.join('version-withSlugs', 'rootResolvedSlug.md'),
|
||||
'/docs/withSlugs/hey/rootResolvedSlug',
|
||||
);
|
||||
await testSlug(
|
||||
versionedDir,
|
||||
path.join('version-withSlugs', 'rootTryToEscapeSlug.md'),
|
||||
'/docs/withSlugs/rootTryToEscapeSlug',
|
||||
);
|
||||
|
||||
await testSlug(
|
||||
versionedDir,
|
||||
path.join('version-withSlugs', 'slugs', 'absoluteSlug.md'),
|
||||
'/docs/withSlugs/absoluteSlug',
|
||||
);
|
||||
await testSlug(
|
||||
versionedDir,
|
||||
path.join('version-withSlugs', 'slugs', 'relativeSlug.md'),
|
||||
'/docs/withSlugs/slugs/relativeSlug',
|
||||
);
|
||||
await testSlug(
|
||||
versionedDir,
|
||||
path.join('version-withSlugs', 'slugs', 'resolvedSlug.md'),
|
||||
'/docs/withSlugs/slugs/hey/resolvedSlug',
|
||||
);
|
||||
await testSlug(
|
||||
versionedDir,
|
||||
path.join('version-withSlugs', 'slugs', 'tryToEscapeSlug.md'),
|
||||
'/docs/withSlugs/tryToEscapeSlug',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import getSlug from '../slug';
|
||||
|
||||
describe('getSlug', () => {
|
||||
test('should default to dirname/id', () => {
|
||||
expect(getSlug({baseID: 'doc', dirName: '/dir'})).toEqual('/dir/doc');
|
||||
expect(getSlug({baseID: 'doc', dirName: '/dir/subdir'})).toEqual(
|
||||
'/dir/subdir/doc',
|
||||
);
|
||||
});
|
||||
|
||||
test('should handle current dir', () => {
|
||||
expect(getSlug({baseID: 'doc', dirName: '.'})).toEqual('/doc');
|
||||
expect(getSlug({baseID: 'doc', dirName: '/'})).toEqual('/doc');
|
||||
});
|
||||
|
||||
test('should resolve absolute slug frontmatter', () => {
|
||||
expect(
|
||||
getSlug({baseID: 'any', dirName: '.', frontmatterSlug: '/abc/def'}),
|
||||
).toEqual('/abc/def');
|
||||
expect(
|
||||
getSlug({baseID: 'any', dirName: './any', frontmatterSlug: '/abc/def'}),
|
||||
).toEqual('/abc/def');
|
||||
expect(
|
||||
getSlug({
|
||||
baseID: 'any',
|
||||
dirName: './any/any',
|
||||
frontmatterSlug: '/abc/def',
|
||||
}),
|
||||
).toEqual('/abc/def');
|
||||
});
|
||||
|
||||
test('should resolve relative slug frontmatter', () => {
|
||||
expect(
|
||||
getSlug({baseID: 'any', dirName: '.', frontmatterSlug: 'abc/def'}),
|
||||
).toEqual('/abc/def');
|
||||
expect(
|
||||
getSlug({baseID: 'any', dirName: '/dir', frontmatterSlug: 'abc/def'}),
|
||||
).toEqual('/dir/abc/def');
|
||||
expect(
|
||||
getSlug({
|
||||
baseID: 'any',
|
||||
dirName: 'unslashedDir',
|
||||
frontmatterSlug: 'abc/def',
|
||||
}),
|
||||
).toEqual('/unslashedDir/abc/def');
|
||||
expect(
|
||||
getSlug({
|
||||
baseID: 'any',
|
||||
dirName: 'dir/subdir',
|
||||
frontmatterSlug: 'abc/def',
|
||||
}),
|
||||
).toEqual('/dir/subdir/abc/def');
|
||||
expect(
|
||||
getSlug({baseID: 'any', dirName: '/dir', frontmatterSlug: './abc/def'}),
|
||||
).toEqual('/dir/abc/def');
|
||||
expect(
|
||||
getSlug({
|
||||
baseID: 'any',
|
||||
dirName: '/dir',
|
||||
frontmatterSlug: './abc/../def',
|
||||
}),
|
||||
).toEqual('/dir/def');
|
||||
expect(
|
||||
getSlug({
|
||||
baseID: 'any',
|
||||
dirName: '/dir/subdir',
|
||||
frontmatterSlug: '../abc/def',
|
||||
}),
|
||||
).toEqual('/dir/abc/def');
|
||||
expect(
|
||||
getSlug({
|
||||
baseID: 'any',
|
||||
dirName: '/dir/subdir',
|
||||
frontmatterSlug: '../../../../../abc/../def',
|
||||
}),
|
||||
).toEqual('/def');
|
||||
});
|
||||
});
|
|
@ -187,7 +187,7 @@ describe('docsVersion', () => {
|
|||
),
|
||||
);
|
||||
expect(versionsPath).toEqual(getVersionsJSONFile(versionedSiteDir));
|
||||
expect(versions).toEqual(['2.0.0', '1.0.1', '1.0.0']);
|
||||
expect(versions).toEqual(['2.0.0', '1.0.1', '1.0.0', 'withSlugs']);
|
||||
expect(consoleMock).toHaveBeenCalledWith('Version 2.0.0 created!');
|
||||
|
||||
copyMock.mockRestore();
|
||||
|
|
|
@ -436,7 +436,10 @@ Available document ids=
|
|||
// to be by version and pick only needed base metadata.
|
||||
if (versioning.enabled) {
|
||||
const docsMetadataByVersion = groupBy(
|
||||
Object.values(content.docsMetadata),
|
||||
// sort to ensure consistent output for tests
|
||||
Object.values(content.docsMetadata).sort((a, b) =>
|
||||
a.id.localeCompare(b.id),
|
||||
),
|
||||
'version',
|
||||
);
|
||||
|
||||
|
|
|
@ -22,9 +22,11 @@ import {
|
|||
Env,
|
||||
VersioningEnv,
|
||||
} from './types';
|
||||
import getSlug from './slug';
|
||||
import {escapeRegExp} from 'lodash';
|
||||
|
||||
function removeVersionPrefix(str: string, version: string): string {
|
||||
return str.replace(new RegExp(`^version-${version}/`), '');
|
||||
return str.replace(new RegExp(`^version-${escapeRegExp(version)}/?`), '');
|
||||
}
|
||||
|
||||
function inferVersion(
|
||||
|
@ -102,8 +104,12 @@ export default async function processMetadata({
|
|||
const fileMarkdownPromise = parseMarkdownFile(filePath);
|
||||
const lastUpdatedPromise = lastUpdated(filePath, options);
|
||||
|
||||
const dirName = path.dirname(source);
|
||||
const version = inferVersion(dirName, versioning);
|
||||
const dirNameWithVersion = path.dirname(source); // ex: version-1.0.0/foo
|
||||
const version = inferVersion(dirNameWithVersion, versioning); // ex: 1.0.0
|
||||
const dirNameWithoutVersion = // ex: foo
|
||||
version && version !== 'next'
|
||||
? removeVersionPrefix(dirNameWithVersion, version)
|
||||
: dirNameWithVersion;
|
||||
|
||||
// The version portion of the url path. Eg: 'next', '1.0.0', and ''.
|
||||
const versionPath =
|
||||
|
@ -122,7 +128,9 @@ export default async function processMetadata({
|
|||
if (baseID.includes('/')) {
|
||||
throw new Error('Document id cannot include "/".');
|
||||
}
|
||||
const id = dirName !== '.' ? `${dirName}/${baseID}` : baseID;
|
||||
|
||||
const id =
|
||||
dirNameWithVersion !== '.' ? `${dirNameWithVersion}/${baseID}` : baseID;
|
||||
const unversionedId = version ? removeVersionPrefix(id, version) : id;
|
||||
|
||||
const isDocsHomePage = unversionedId === homePageId;
|
||||
|
@ -132,34 +140,24 @@ export default async function processMetadata({
|
|||
);
|
||||
}
|
||||
|
||||
const baseSlug: string = frontMatter.slug || baseID;
|
||||
if (baseSlug.includes('/')) {
|
||||
throw new Error('Document slug cannot include "/".');
|
||||
}
|
||||
const slug = dirName !== '.' ? `${dirName}/${baseSlug}` : baseSlug;
|
||||
const docSlug = isDocsHomePage
|
||||
? '/'
|
||||
: getSlug({
|
||||
baseID,
|
||||
dirName: dirNameWithoutVersion,
|
||||
frontmatterSlug: frontMatter.slug,
|
||||
});
|
||||
|
||||
// Default title is the id.
|
||||
const title: string = frontMatter.title || baseID;
|
||||
|
||||
const description: string = frontMatter.description || excerpt;
|
||||
|
||||
// The last portion of the url path. Eg: 'foo/bar', 'bar'.
|
||||
let routePath;
|
||||
if (isDocsHomePage) {
|
||||
// TODO can we remove this trailing / ?
|
||||
// Seems it's not that easy...
|
||||
// Related to https://github.com/facebook/docusaurus/issues/2917
|
||||
routePath = '/';
|
||||
} else {
|
||||
routePath =
|
||||
version && version !== 'next' ? removeVersionPrefix(slug, version) : slug;
|
||||
}
|
||||
|
||||
const permalink = normalizeUrl([
|
||||
baseUrl,
|
||||
routeBasePath,
|
||||
versionPath,
|
||||
routePath,
|
||||
docSlug,
|
||||
]);
|
||||
|
||||
const {lastUpdatedAt, lastUpdatedBy} = await lastUpdatedPromise;
|
||||
|
|
41
packages/docusaurus-plugin-content-docs/src/slug.ts
Normal file
41
packages/docusaurus-plugin-content-docs/src/slug.ts
Normal file
|
@ -0,0 +1,41 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import {
|
||||
addLeadingSlash,
|
||||
addTrailingSlash,
|
||||
isValidPathname,
|
||||
resolvePathname,
|
||||
} from '@docusaurus/utils';
|
||||
|
||||
export default function getSlug({
|
||||
baseID,
|
||||
frontmatterSlug,
|
||||
dirName,
|
||||
}: {
|
||||
baseID: string;
|
||||
frontmatterSlug?: string;
|
||||
dirName: string;
|
||||
}) {
|
||||
const baseSlug: string = frontmatterSlug || baseID;
|
||||
let slug: string;
|
||||
if (baseSlug.startsWith('/')) {
|
||||
slug = baseSlug;
|
||||
} else {
|
||||
const resolveDirname =
|
||||
dirName === '.' ? '/' : addLeadingSlash(addTrailingSlash(dirName));
|
||||
slug = resolvePathname(baseSlug, resolveDirname);
|
||||
}
|
||||
|
||||
if (!isValidPathname(slug)) {
|
||||
throw new Error(
|
||||
`Unable to resolve valid document slug. Maybe your slug frontmatter is incorrect? Doc id=${baseID} / dirName=${dirName} / frontmatterSlug=${frontmatterSlug} => bad result slug=${slug}`,
|
||||
);
|
||||
}
|
||||
|
||||
return slug;
|
||||
}
|
|
@ -126,7 +126,7 @@ export interface MetadataRaw extends LastUpdateData {
|
|||
source: string;
|
||||
permalink: string;
|
||||
sidebar_label?: string;
|
||||
editUrl?: string;
|
||||
editUrl?: string | null;
|
||||
version?: string;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue