mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-10 07:37:19 +02:00
feat(content-docs): last_update front matter (#7461)
Co-authored-by: Joshua Chen <sidachen2003@gmail.com> Co-authored-by: sebastienlorber <lorber.sebastien@gmail.com>
This commit is contained in:
parent
a469ae3d63
commit
4f26a1911a
15 changed files with 499 additions and 36 deletions
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
title: Custom Last Update
|
||||||
|
last_update:
|
||||||
|
author: Custom Author
|
||||||
|
date: 1/1/2000
|
||||||
|
---
|
||||||
|
|
||||||
|
Custom last update
|
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
title: Last Update Author Only
|
||||||
|
last_update:
|
||||||
|
author: Custom Author
|
||||||
|
---
|
||||||
|
|
||||||
|
Only custom author, so it will still use the date from Git
|
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
title: Last Update Date Only
|
||||||
|
last_update:
|
||||||
|
date: 1/1/2000
|
||||||
|
---
|
||||||
|
|
||||||
|
Only custom date, so it will still use the author from Git
|
|
@ -3,13 +3,24 @@
|
||||||
exports[`simple site custom pagination 1`] = `
|
exports[`simple site custom pagination 1`] = `
|
||||||
{
|
{
|
||||||
"pagination": [
|
"pagination": [
|
||||||
|
{
|
||||||
|
"id": "customLastUpdate",
|
||||||
|
"next": {
|
||||||
|
"permalink": "/docs/doc with space",
|
||||||
|
"title": "Hoo hoo, if this path tricks you...",
|
||||||
|
},
|
||||||
|
"prev": undefined,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "doc with space",
|
"id": "doc with space",
|
||||||
"next": {
|
"next": {
|
||||||
"permalink": "/docs/doc-draft",
|
"permalink": "/docs/doc-draft",
|
||||||
"title": "doc-draft",
|
"title": "doc-draft",
|
||||||
},
|
},
|
||||||
"prev": undefined,
|
"prev": {
|
||||||
|
"permalink": "/docs/customLastUpdate",
|
||||||
|
"title": "Custom Last Update",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "doc-draft",
|
"id": "doc-draft",
|
||||||
|
@ -63,14 +74,36 @@ exports[`simple site custom pagination 1`] = `
|
||||||
{
|
{
|
||||||
"id": "ipsum",
|
"id": "ipsum",
|
||||||
"next": {
|
"next": {
|
||||||
"permalink": "/docs/lorem",
|
"permalink": "/docs/lastUpdateAuthorOnly",
|
||||||
"title": "lorem",
|
"title": "Last Update Author Only",
|
||||||
},
|
},
|
||||||
"prev": {
|
"prev": {
|
||||||
"permalink": "/docs/",
|
"permalink": "/docs/",
|
||||||
"title": "Hello sidebar_label",
|
"title": "Hello sidebar_label",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "lastUpdateAuthorOnly",
|
||||||
|
"next": {
|
||||||
|
"permalink": "/docs/lastUpdateDateOnly",
|
||||||
|
"title": "Last Update Date Only",
|
||||||
|
},
|
||||||
|
"prev": {
|
||||||
|
"permalink": "/docs/ipsum",
|
||||||
|
"title": "ipsum",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "lastUpdateDateOnly",
|
||||||
|
"next": {
|
||||||
|
"permalink": "/docs/lorem",
|
||||||
|
"title": "lorem",
|
||||||
|
},
|
||||||
|
"prev": {
|
||||||
|
"permalink": "/docs/lastUpdateAuthorOnly",
|
||||||
|
"title": "Last Update Author Only",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "lorem",
|
"id": "lorem",
|
||||||
"next": {
|
"next": {
|
||||||
|
@ -78,8 +111,8 @@ exports[`simple site custom pagination 1`] = `
|
||||||
"title": "rootAbsoluteSlug",
|
"title": "rootAbsoluteSlug",
|
||||||
},
|
},
|
||||||
"prev": {
|
"prev": {
|
||||||
"permalink": "/docs/ipsum",
|
"permalink": "/docs/lastUpdateDateOnly",
|
||||||
"title": "ipsum",
|
"title": "Last Update Date Only",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -170,6 +203,10 @@ exports[`simple site custom pagination 1`] = `
|
||||||
],
|
],
|
||||||
"sidebars": {
|
"sidebars": {
|
||||||
"defaultSidebar": [
|
"defaultSidebar": [
|
||||||
|
{
|
||||||
|
"id": "customLastUpdate",
|
||||||
|
"type": "doc",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "doc with space",
|
"id": "doc with space",
|
||||||
"type": "doc",
|
"type": "doc",
|
||||||
|
@ -208,6 +245,14 @@ exports[`simple site custom pagination 1`] = `
|
||||||
"id": "ipsum",
|
"id": "ipsum",
|
||||||
"type": "doc",
|
"type": "doc",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "lastUpdateAuthorOnly",
|
||||||
|
"type": "doc",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "lastUpdateDateOnly",
|
||||||
|
"type": "doc",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "lorem",
|
"id": "lorem",
|
||||||
"type": "doc",
|
"type": "doc",
|
||||||
|
|
|
@ -22,6 +22,7 @@ These sidebar document ids do not exist:
|
||||||
- nonExistent
|
- nonExistent
|
||||||
|
|
||||||
Available document ids are:
|
Available document ids are:
|
||||||
|
- customLastUpdate
|
||||||
- doc with space
|
- doc with space
|
||||||
- doc-draft
|
- doc-draft
|
||||||
- foo/bar
|
- foo/bar
|
||||||
|
@ -29,6 +30,8 @@ Available document ids are:
|
||||||
- headingAsTitle
|
- headingAsTitle
|
||||||
- hello
|
- hello
|
||||||
- ipsum
|
- ipsum
|
||||||
|
- lastUpdateAuthorOnly
|
||||||
|
- lastUpdateDateOnly
|
||||||
- lorem
|
- lorem
|
||||||
- rootAbsoluteSlug
|
- rootAbsoluteSlug
|
||||||
- rootRelativeSlug
|
- rootRelativeSlug
|
||||||
|
@ -267,6 +270,11 @@ exports[`simple website content 5`] = `
|
||||||
"versions": [
|
"versions": [
|
||||||
{
|
{
|
||||||
"docs": [
|
"docs": [
|
||||||
|
{
|
||||||
|
"id": "customLastUpdate",
|
||||||
|
"path": "/docs/customLastUpdate",
|
||||||
|
"sidebar": undefined,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "doc with space",
|
"id": "doc with space",
|
||||||
"path": "/docs/doc with space",
|
"path": "/docs/doc with space",
|
||||||
|
@ -302,6 +310,16 @@ exports[`simple website content 5`] = `
|
||||||
"path": "/docs/ipsum",
|
"path": "/docs/ipsum",
|
||||||
"sidebar": undefined,
|
"sidebar": undefined,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "lastUpdateAuthorOnly",
|
||||||
|
"path": "/docs/lastUpdateAuthorOnly",
|
||||||
|
"sidebar": undefined,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "lastUpdateDateOnly",
|
||||||
|
"path": "/docs/lastUpdateDateOnly",
|
||||||
|
"sidebar": undefined,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "lorem",
|
"id": "lorem",
|
||||||
"path": "/docs/lorem",
|
"path": "/docs/lorem",
|
||||||
|
@ -390,6 +408,26 @@ exports[`simple website content: data 1`] = `
|
||||||
"permalink": "/docs/rootAbsoluteSlug"
|
"permalink": "/docs/rootAbsoluteSlug"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}",
|
||||||
|
"site-docs-custom-last-update-md-b8d.json": "{
|
||||||
|
"unversionedId": "customLastUpdate",
|
||||||
|
"id": "customLastUpdate",
|
||||||
|
"title": "Custom Last Update",
|
||||||
|
"description": "Custom last update",
|
||||||
|
"source": "@site/docs/customLastUpdate.md",
|
||||||
|
"sourceDirName": ".",
|
||||||
|
"slug": "/customLastUpdate",
|
||||||
|
"permalink": "/docs/customLastUpdate",
|
||||||
|
"draft": false,
|
||||||
|
"tags": [],
|
||||||
|
"version": "current",
|
||||||
|
"frontMatter": {
|
||||||
|
"title": "Custom Last Update",
|
||||||
|
"last_update": {
|
||||||
|
"author": "Custom Author",
|
||||||
|
"date": "1/1/2000"
|
||||||
|
}
|
||||||
|
}
|
||||||
}",
|
}",
|
||||||
"site-docs-doc-draft-md-584.json": "{
|
"site-docs-doc-draft-md-584.json": "{
|
||||||
"unversionedId": "doc-draft",
|
"unversionedId": "doc-draft",
|
||||||
|
@ -563,6 +601,44 @@ exports[`simple website content: data 1`] = `
|
||||||
"frontMatter": {
|
"frontMatter": {
|
||||||
"custom_edit_url": null
|
"custom_edit_url": null
|
||||||
}
|
}
|
||||||
|
}",
|
||||||
|
"site-docs-last-update-author-only-md-352.json": "{
|
||||||
|
"unversionedId": "lastUpdateAuthorOnly",
|
||||||
|
"id": "lastUpdateAuthorOnly",
|
||||||
|
"title": "Last Update Author Only",
|
||||||
|
"description": "Only custom author, so it will still use the date from Git",
|
||||||
|
"source": "@site/docs/lastUpdateAuthorOnly.md",
|
||||||
|
"sourceDirName": ".",
|
||||||
|
"slug": "/lastUpdateAuthorOnly",
|
||||||
|
"permalink": "/docs/lastUpdateAuthorOnly",
|
||||||
|
"draft": false,
|
||||||
|
"tags": [],
|
||||||
|
"version": "current",
|
||||||
|
"frontMatter": {
|
||||||
|
"title": "Last Update Author Only",
|
||||||
|
"last_update": {
|
||||||
|
"author": "Custom Author"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}",
|
||||||
|
"site-docs-last-update-date-only-md-987.json": "{
|
||||||
|
"unversionedId": "lastUpdateDateOnly",
|
||||||
|
"id": "lastUpdateDateOnly",
|
||||||
|
"title": "Last Update Date Only",
|
||||||
|
"description": "Only custom date, so it will still use the author from Git",
|
||||||
|
"source": "@site/docs/lastUpdateDateOnly.md",
|
||||||
|
"sourceDirName": ".",
|
||||||
|
"slug": "/lastUpdateDateOnly",
|
||||||
|
"permalink": "/docs/lastUpdateDateOnly",
|
||||||
|
"draft": false,
|
||||||
|
"tags": [],
|
||||||
|
"version": "current",
|
||||||
|
"frontMatter": {
|
||||||
|
"title": "Last Update Date Only",
|
||||||
|
"last_update": {
|
||||||
|
"date": "1/1/2000"
|
||||||
|
}
|
||||||
|
}
|
||||||
}",
|
}",
|
||||||
"site-docs-lorem-md-b27.json": "{
|
"site-docs-lorem-md-b27.json": "{
|
||||||
"unversionedId": "lorem",
|
"unversionedId": "lorem",
|
||||||
|
@ -924,6 +1000,11 @@ exports[`simple website content: data 1`] = `
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"docs": {
|
"docs": {
|
||||||
|
"customLastUpdate": {
|
||||||
|
"id": "customLastUpdate",
|
||||||
|
"title": "Custom Last Update",
|
||||||
|
"description": "Custom last update"
|
||||||
|
},
|
||||||
"doc with space": {
|
"doc with space": {
|
||||||
"id": "doc with space",
|
"id": "doc with space",
|
||||||
"title": "Hoo hoo, if this path tricks you...",
|
"title": "Hoo hoo, if this path tricks you...",
|
||||||
|
@ -963,6 +1044,16 @@ exports[`simple website content: data 1`] = `
|
||||||
"title": "ipsum",
|
"title": "ipsum",
|
||||||
"description": "Lorem ipsum."
|
"description": "Lorem ipsum."
|
||||||
},
|
},
|
||||||
|
"lastUpdateAuthorOnly": {
|
||||||
|
"id": "lastUpdateAuthorOnly",
|
||||||
|
"title": "Last Update Author Only",
|
||||||
|
"description": "Only custom author, so it will still use the date from Git"
|
||||||
|
},
|
||||||
|
"lastUpdateDateOnly": {
|
||||||
|
"id": "lastUpdateDateOnly",
|
||||||
|
"title": "Last Update Date Only",
|
||||||
|
"description": "Only custom date, so it will still use the author from Git"
|
||||||
|
},
|
||||||
"lorem": {
|
"lorem": {
|
||||||
"id": "lorem",
|
"id": "lorem",
|
||||||
"title": "lorem",
|
"title": "lorem",
|
||||||
|
@ -1026,6 +1117,11 @@ exports[`simple website content: global data 1`] = `
|
||||||
"versions": [
|
"versions": [
|
||||||
{
|
{
|
||||||
"docs": [
|
"docs": [
|
||||||
|
{
|
||||||
|
"id": "customLastUpdate",
|
||||||
|
"path": "/docs/customLastUpdate",
|
||||||
|
"sidebar": undefined,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "doc with space",
|
"id": "doc with space",
|
||||||
"path": "/docs/doc with space",
|
"path": "/docs/doc with space",
|
||||||
|
@ -1061,6 +1157,16 @@ exports[`simple website content: global data 1`] = `
|
||||||
"path": "/docs/ipsum",
|
"path": "/docs/ipsum",
|
||||||
"sidebar": undefined,
|
"sidebar": undefined,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "lastUpdateAuthorOnly",
|
||||||
|
"path": "/docs/lastUpdateAuthorOnly",
|
||||||
|
"sidebar": undefined,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "lastUpdateDateOnly",
|
||||||
|
"path": "/docs/lastUpdateDateOnly",
|
||||||
|
"sidebar": undefined,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "lorem",
|
"id": "lorem",
|
||||||
"path": "/docs/lorem",
|
"path": "/docs/lorem",
|
||||||
|
@ -1202,6 +1308,14 @@ exports[`simple website content: route config 1`] = `
|
||||||
"path": "/docs/category/slugs",
|
"path": "/docs/category/slugs",
|
||||||
"sidebar": "docs",
|
"sidebar": "docs",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"component": "@theme/DocItem",
|
||||||
|
"exact": true,
|
||||||
|
"modules": {
|
||||||
|
"content": "@site/docs/customLastUpdate.md",
|
||||||
|
},
|
||||||
|
"path": "/docs/customLastUpdate",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"component": "@theme/DocItem",
|
"component": "@theme/DocItem",
|
||||||
"exact": true,
|
"exact": true,
|
||||||
|
@ -1262,6 +1376,22 @@ exports[`simple website content: route config 1`] = `
|
||||||
},
|
},
|
||||||
"path": "/docs/ipsum",
|
"path": "/docs/ipsum",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"component": "@theme/DocItem",
|
||||||
|
"exact": true,
|
||||||
|
"modules": {
|
||||||
|
"content": "@site/docs/lastUpdateAuthorOnly.md",
|
||||||
|
},
|
||||||
|
"path": "/docs/lastUpdateAuthorOnly",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"component": "@theme/DocItem",
|
||||||
|
"exact": true,
|
||||||
|
"modules": {
|
||||||
|
"content": "@site/docs/lastUpdateDateOnly.md",
|
||||||
|
},
|
||||||
|
"path": "/docs/lastUpdateDateOnly",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"component": "@theme/DocItem",
|
"component": "@theme/DocItem",
|
||||||
"exact": true,
|
"exact": true,
|
||||||
|
|
|
@ -57,7 +57,6 @@ ${markdown}
|
||||||
return {
|
return {
|
||||||
source,
|
source,
|
||||||
content,
|
content,
|
||||||
lastUpdate: {},
|
|
||||||
contentPath: 'docs',
|
contentPath: 'docs',
|
||||||
filePath: source,
|
filePath: source,
|
||||||
};
|
};
|
||||||
|
@ -79,7 +78,7 @@ function createTestUtils({
|
||||||
env = 'production',
|
env = 'production',
|
||||||
}: TestUtilsArg) {
|
}: TestUtilsArg) {
|
||||||
async function readDoc(docFileSource: string) {
|
async function readDoc(docFileSource: string) {
|
||||||
return readDocFile(versionMetadata, docFileSource, options);
|
return readDocFile(versionMetadata, docFileSource);
|
||||||
}
|
}
|
||||||
async function processDocFile(docFileArg: DocFile | string) {
|
async function processDocFile(docFileArg: DocFile | string) {
|
||||||
const docFile: DocFile =
|
const docFile: DocFile =
|
||||||
|
@ -119,7 +118,7 @@ function createTestUtils({
|
||||||
|
|
||||||
async function testSlug(docFileSource: string, expectedPermalink: string) {
|
async function testSlug(docFileSource: string, expectedPermalink: string) {
|
||||||
const docFile = await readDoc(docFileSource);
|
const docFile = await readDoc(docFileSource);
|
||||||
const metadata = processDocMetadata({
|
const metadata = await processDocMetadata({
|
||||||
docFile,
|
docFile,
|
||||||
versionMetadata,
|
versionMetadata,
|
||||||
context,
|
context,
|
||||||
|
@ -137,7 +136,8 @@ function createTestUtils({
|
||||||
}[];
|
}[];
|
||||||
sidebars: Sidebars;
|
sidebars: Sidebars;
|
||||||
}> {
|
}> {
|
||||||
const rawDocs = docFiles.map((docFile) =>
|
const rawDocs = await Promise.all(
|
||||||
|
docFiles.map(async (docFile) =>
|
||||||
processDocMetadata({
|
processDocMetadata({
|
||||||
docFile,
|
docFile,
|
||||||
versionMetadata,
|
versionMetadata,
|
||||||
|
@ -145,6 +145,7 @@ function createTestUtils({
|
||||||
options,
|
options,
|
||||||
env: 'production',
|
env: 'production',
|
||||||
}),
|
}),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
const sidebars = await loadSidebars(versionMetadata.sidebarFilePath, {
|
const sidebars = await loadSidebars(versionMetadata.sidebarFilePath, {
|
||||||
sidebarItemsGenerator: ({defaultSidebarItemsGenerator, ...args}) =>
|
sidebarItemsGenerator: ({defaultSidebarItemsGenerator, ...args}) =>
|
||||||
|
@ -230,6 +231,9 @@ describe('simple site', () => {
|
||||||
'headingAsTitle.md',
|
'headingAsTitle.md',
|
||||||
'doc with space.md',
|
'doc with space.md',
|
||||||
'doc-draft.md',
|
'doc-draft.md',
|
||||||
|
'customLastUpdate.md',
|
||||||
|
'lastUpdateAuthorOnly.md',
|
||||||
|
'lastUpdateDateOnly.md',
|
||||||
'foo/bar.md',
|
'foo/bar.md',
|
||||||
'foo/baz.md',
|
'foo/baz.md',
|
||||||
'slugs/absoluteSlug.md',
|
'slugs/absoluteSlug.md',
|
||||||
|
@ -481,6 +485,164 @@ describe('simple site', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('docs with last_update front matter', async () => {
|
||||||
|
const {siteDir, context, options, currentVersion, createTestUtilsPartial} =
|
||||||
|
await loadSite({
|
||||||
|
options: {
|
||||||
|
showLastUpdateAuthor: true,
|
||||||
|
showLastUpdateTime: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const testUtilsLocal = createTestUtilsPartial({
|
||||||
|
siteDir,
|
||||||
|
context,
|
||||||
|
options,
|
||||||
|
versionMetadata: currentVersion,
|
||||||
|
});
|
||||||
|
|
||||||
|
await testUtilsLocal.testMeta('customLastUpdate.md', {
|
||||||
|
version: 'current',
|
||||||
|
id: 'customLastUpdate',
|
||||||
|
unversionedId: 'customLastUpdate',
|
||||||
|
sourceDirName: '.',
|
||||||
|
permalink: '/docs/customLastUpdate',
|
||||||
|
slug: '/customLastUpdate',
|
||||||
|
title: 'Custom Last Update',
|
||||||
|
description: 'Custom last update',
|
||||||
|
frontMatter: {
|
||||||
|
last_update: {
|
||||||
|
author: 'Custom Author',
|
||||||
|
date: '1/1/2000',
|
||||||
|
},
|
||||||
|
title: 'Custom Last Update',
|
||||||
|
},
|
||||||
|
lastUpdatedAt: new Date('1/1/2000').getTime() / 1000,
|
||||||
|
formattedLastUpdatedAt: '1/1/2000',
|
||||||
|
lastUpdatedBy: 'Custom Author',
|
||||||
|
sidebarPosition: undefined,
|
||||||
|
tags: [],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('docs with only last_update author front matter', async () => {
|
||||||
|
const {siteDir, context, options, currentVersion, createTestUtilsPartial} =
|
||||||
|
await loadSite({
|
||||||
|
options: {
|
||||||
|
showLastUpdateAuthor: true,
|
||||||
|
showLastUpdateTime: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const testUtilsLocal = createTestUtilsPartial({
|
||||||
|
siteDir,
|
||||||
|
context,
|
||||||
|
options,
|
||||||
|
versionMetadata: currentVersion,
|
||||||
|
});
|
||||||
|
|
||||||
|
await testUtilsLocal.testMeta('lastUpdateAuthorOnly.md', {
|
||||||
|
version: 'current',
|
||||||
|
id: 'lastUpdateAuthorOnly',
|
||||||
|
unversionedId: 'lastUpdateAuthorOnly',
|
||||||
|
sourceDirName: '.',
|
||||||
|
permalink: '/docs/lastUpdateAuthorOnly',
|
||||||
|
slug: '/lastUpdateAuthorOnly',
|
||||||
|
title: 'Last Update Author Only',
|
||||||
|
description: 'Only custom author, so it will still use the date from Git',
|
||||||
|
frontMatter: {
|
||||||
|
last_update: {
|
||||||
|
author: 'Custom Author',
|
||||||
|
},
|
||||||
|
title: 'Last Update Author Only',
|
||||||
|
},
|
||||||
|
lastUpdatedAt: 1539502055,
|
||||||
|
formattedLastUpdatedAt: '10/14/2018',
|
||||||
|
lastUpdatedBy: 'Custom Author',
|
||||||
|
sidebarPosition: undefined,
|
||||||
|
tags: [],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('docs with only last_update date front matter', async () => {
|
||||||
|
const {siteDir, context, options, currentVersion, createTestUtilsPartial} =
|
||||||
|
await loadSite({
|
||||||
|
options: {
|
||||||
|
showLastUpdateAuthor: true,
|
||||||
|
showLastUpdateTime: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const testUtilsLocal = createTestUtilsPartial({
|
||||||
|
siteDir,
|
||||||
|
context,
|
||||||
|
options,
|
||||||
|
versionMetadata: currentVersion,
|
||||||
|
});
|
||||||
|
|
||||||
|
await testUtilsLocal.testMeta('lastUpdateDateOnly.md', {
|
||||||
|
version: 'current',
|
||||||
|
id: 'lastUpdateDateOnly',
|
||||||
|
unversionedId: 'lastUpdateDateOnly',
|
||||||
|
sourceDirName: '.',
|
||||||
|
permalink: '/docs/lastUpdateDateOnly',
|
||||||
|
slug: '/lastUpdateDateOnly',
|
||||||
|
title: 'Last Update Date Only',
|
||||||
|
description: 'Only custom date, so it will still use the author from Git',
|
||||||
|
frontMatter: {
|
||||||
|
last_update: {
|
||||||
|
date: '1/1/2000',
|
||||||
|
},
|
||||||
|
title: 'Last Update Date Only',
|
||||||
|
},
|
||||||
|
lastUpdatedAt: new Date('1/1/2000').getTime() / 1000,
|
||||||
|
formattedLastUpdatedAt: '1/1/2000',
|
||||||
|
lastUpdatedBy: 'Author',
|
||||||
|
sidebarPosition: undefined,
|
||||||
|
tags: [],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('docs with last_update front matter disabled', async () => {
|
||||||
|
const {siteDir, context, options, currentVersion, createTestUtilsPartial} =
|
||||||
|
await loadSite({
|
||||||
|
options: {
|
||||||
|
showLastUpdateAuthor: false,
|
||||||
|
showLastUpdateTime: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const testUtilsLocal = createTestUtilsPartial({
|
||||||
|
siteDir,
|
||||||
|
context,
|
||||||
|
options,
|
||||||
|
versionMetadata: currentVersion,
|
||||||
|
});
|
||||||
|
|
||||||
|
await testUtilsLocal.testMeta('customLastUpdate.md', {
|
||||||
|
version: 'current',
|
||||||
|
id: 'customLastUpdate',
|
||||||
|
unversionedId: 'customLastUpdate',
|
||||||
|
sourceDirName: '.',
|
||||||
|
permalink: '/docs/customLastUpdate',
|
||||||
|
slug: '/customLastUpdate',
|
||||||
|
title: 'Custom Last Update',
|
||||||
|
description: 'Custom last update',
|
||||||
|
frontMatter: {
|
||||||
|
last_update: {
|
||||||
|
author: 'Custom Author',
|
||||||
|
date: '1/1/2000',
|
||||||
|
},
|
||||||
|
title: 'Custom Last Update',
|
||||||
|
},
|
||||||
|
lastUpdatedAt: undefined,
|
||||||
|
formattedLastUpdatedAt: undefined,
|
||||||
|
lastUpdatedBy: undefined,
|
||||||
|
sidebarPosition: undefined,
|
||||||
|
tags: [],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('docs with slugs', async () => {
|
it('docs with slugs', async () => {
|
||||||
const {defaultTestUtils} = await loadSite();
|
const {defaultTestUtils} = await loadSite();
|
||||||
|
|
||||||
|
|
|
@ -396,3 +396,52 @@ describe('validateDocFrontMatter draft', () => {
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('validateDocFrontMatter last_update', () => {
|
||||||
|
testField({
|
||||||
|
prefix: 'last_update',
|
||||||
|
validFrontMatters: [
|
||||||
|
{last_update: undefined},
|
||||||
|
{last_update: {author: 'test author', date: undefined}},
|
||||||
|
{last_update: {author: undefined, date: '1/1/2000'}},
|
||||||
|
{last_update: {author: undefined, date: new Date('1/1/2000')}},
|
||||||
|
{last_update: {author: 'test author', date: '1/1/2000'}},
|
||||||
|
{last_update: {author: 'test author', date: '1995-12-17T03:24:00'}},
|
||||||
|
{last_update: {author: undefined, date: 'December 17, 1995 03:24:00'}},
|
||||||
|
],
|
||||||
|
invalidFrontMatters: [
|
||||||
|
[
|
||||||
|
{last_update: null},
|
||||||
|
'does not look like a valid front matter FileChange object. Please use a FileChange object (with an author and/or date).',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{last_update: {}},
|
||||||
|
'does not look like a valid front matter FileChange object. Please use a FileChange object (with an author and/or date).',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{last_update: ''},
|
||||||
|
'does not look like a valid front matter FileChange object. Please use a FileChange object (with an author and/or date).',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{last_update: {invalid: 'key'}},
|
||||||
|
'does not look like a valid front matter FileChange object. Please use a FileChange object (with an author and/or date).',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{last_update: {author: 'test author', date: 'I am not a date :('}},
|
||||||
|
'must be a valid date',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{last_update: {author: 'test author', date: '2011-10-45'}},
|
||||||
|
'must be a valid date',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{last_update: {author: 'test author', date: '2011-0-10'}},
|
||||||
|
'must be a valid date',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{last_update: {author: 'test author', date: ''}},
|
||||||
|
'must be a valid date',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
@ -37,6 +37,7 @@ import type {
|
||||||
VersionMetadata,
|
VersionMetadata,
|
||||||
DocFrontMatter,
|
DocFrontMatter,
|
||||||
LoadedVersion,
|
LoadedVersion,
|
||||||
|
FileChange,
|
||||||
} from '@docusaurus/plugin-content-docs';
|
} from '@docusaurus/plugin-content-docs';
|
||||||
import type {LoadContext} from '@docusaurus/types';
|
import type {LoadContext} from '@docusaurus/types';
|
||||||
import type {SidebarsUtils} from './sidebars/utils';
|
import type {SidebarsUtils} from './sidebars/utils';
|
||||||
|
@ -50,9 +51,21 @@ type LastUpdateOptions = Pick<
|
||||||
async function readLastUpdateData(
|
async function readLastUpdateData(
|
||||||
filePath: string,
|
filePath: string,
|
||||||
options: LastUpdateOptions,
|
options: LastUpdateOptions,
|
||||||
|
lastUpdateFrontMatter: FileChange | undefined,
|
||||||
): Promise<LastUpdateData> {
|
): Promise<LastUpdateData> {
|
||||||
const {showLastUpdateAuthor, showLastUpdateTime} = options;
|
const {showLastUpdateAuthor, showLastUpdateTime} = options;
|
||||||
if (showLastUpdateAuthor || showLastUpdateTime) {
|
if (showLastUpdateAuthor || showLastUpdateTime) {
|
||||||
|
const frontMatterTimestamp = lastUpdateFrontMatter?.date
|
||||||
|
? new Date(lastUpdateFrontMatter.date).getTime() / 1000
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
if (lastUpdateFrontMatter?.author && lastUpdateFrontMatter.date) {
|
||||||
|
return {
|
||||||
|
lastUpdatedAt: frontMatterTimestamp,
|
||||||
|
lastUpdatedBy: lastUpdateFrontMatter.author,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Use fake data in dev for faster development.
|
// Use fake data in dev for faster development.
|
||||||
const fileLastUpdateData =
|
const fileLastUpdateData =
|
||||||
process.env.NODE_ENV === 'production'
|
process.env.NODE_ENV === 'production'
|
||||||
|
@ -61,15 +74,17 @@ async function readLastUpdateData(
|
||||||
author: 'Author',
|
author: 'Author',
|
||||||
timestamp: 1539502055,
|
timestamp: 1539502055,
|
||||||
};
|
};
|
||||||
|
const {author, timestamp} = fileLastUpdateData ?? {};
|
||||||
|
|
||||||
if (fileLastUpdateData) {
|
|
||||||
const {author, timestamp} = fileLastUpdateData;
|
|
||||||
return {
|
return {
|
||||||
lastUpdatedAt: showLastUpdateTime ? timestamp : undefined,
|
lastUpdatedBy: showLastUpdateAuthor
|
||||||
lastUpdatedBy: showLastUpdateAuthor ? author : undefined,
|
? lastUpdateFrontMatter?.author ?? author
|
||||||
|
: undefined,
|
||||||
|
lastUpdatedAt: showLastUpdateTime
|
||||||
|
? frontMatterTimestamp ?? timestamp
|
||||||
|
: undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -80,7 +95,6 @@ export async function readDocFile(
|
||||||
'contentPath' | 'contentPathLocalized'
|
'contentPath' | 'contentPathLocalized'
|
||||||
>,
|
>,
|
||||||
source: string,
|
source: string,
|
||||||
options: LastUpdateOptions,
|
|
||||||
): Promise<DocFile> {
|
): Promise<DocFile> {
|
||||||
const contentPath = await getFolderContainingFile(
|
const contentPath = await getFolderContainingFile(
|
||||||
getContentPathList(versionMetadata),
|
getContentPathList(versionMetadata),
|
||||||
|
@ -89,11 +103,8 @@ export async function readDocFile(
|
||||||
|
|
||||||
const filePath = path.join(contentPath, source);
|
const filePath = path.join(contentPath, source);
|
||||||
|
|
||||||
const [content, lastUpdate] = await Promise.all([
|
const content = await fs.readFile(filePath, 'utf-8');
|
||||||
fs.readFile(filePath, 'utf-8'),
|
return {source, content, contentPath, filePath};
|
||||||
readLastUpdateData(filePath, options),
|
|
||||||
]);
|
|
||||||
return {source, content, lastUpdate, contentPath, filePath};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function readVersionDocs(
|
export async function readVersionDocs(
|
||||||
|
@ -108,7 +119,7 @@ export async function readVersionDocs(
|
||||||
ignore: options.exclude,
|
ignore: options.exclude,
|
||||||
});
|
});
|
||||||
return Promise.all(
|
return Promise.all(
|
||||||
sources.map((source) => readDocFile(versionMetadata, source, options)),
|
sources.map((source) => readDocFile(versionMetadata, source)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,7 +136,7 @@ function isDraftForEnvironment({
|
||||||
return (env === 'production' && frontMatter.draft) ?? false;
|
return (env === 'production' && frontMatter.draft) ?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function doProcessDocMetadata({
|
async function doProcessDocMetadata({
|
||||||
docFile,
|
docFile,
|
||||||
versionMetadata,
|
versionMetadata,
|
||||||
context,
|
context,
|
||||||
|
@ -137,8 +148,8 @@ function doProcessDocMetadata({
|
||||||
context: LoadContext;
|
context: LoadContext;
|
||||||
options: MetadataOptions;
|
options: MetadataOptions;
|
||||||
env: DocEnv;
|
env: DocEnv;
|
||||||
}): DocMetadataBase {
|
}): Promise<DocMetadataBase> {
|
||||||
const {source, content, lastUpdate, contentPath, filePath} = docFile;
|
const {source, content, contentPath, filePath} = docFile;
|
||||||
const {siteDir, i18n} = context;
|
const {siteDir, i18n} = context;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
@ -155,8 +166,15 @@ function doProcessDocMetadata({
|
||||||
// (01-MyFolder/01-MyDoc.md => MyFolder/MyDoc)
|
// (01-MyFolder/01-MyDoc.md => MyFolder/MyDoc)
|
||||||
// but allow to disable this behavior with front matter
|
// but allow to disable this behavior with front matter
|
||||||
parse_number_prefixes: parseNumberPrefixes = true,
|
parse_number_prefixes: parseNumberPrefixes = true,
|
||||||
|
last_update: lastUpdateFrontMatter,
|
||||||
} = frontMatter;
|
} = frontMatter;
|
||||||
|
|
||||||
|
const lastUpdate = await readLastUpdateData(
|
||||||
|
filePath,
|
||||||
|
options,
|
||||||
|
lastUpdateFrontMatter,
|
||||||
|
);
|
||||||
|
|
||||||
// E.g. api/plugins/myDoc -> myDoc; myDoc -> myDoc
|
// E.g. api/plugins/myDoc -> myDoc; myDoc -> myDoc
|
||||||
const sourceFileNameWithoutExtension = path.basename(
|
const sourceFileNameWithoutExtension = path.basename(
|
||||||
source,
|
source,
|
||||||
|
@ -287,7 +305,7 @@ export function processDocMetadata(args: {
|
||||||
context: LoadContext;
|
context: LoadContext;
|
||||||
options: MetadataOptions;
|
options: MetadataOptions;
|
||||||
env: DocEnv;
|
env: DocEnv;
|
||||||
}): DocMetadataBase {
|
}): Promise<DocMetadataBase> {
|
||||||
try {
|
try {
|
||||||
return doProcessDocMetadata(args);
|
return doProcessDocMetadata(args);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
|
@ -14,6 +14,9 @@ import {
|
||||||
} from '@docusaurus/utils-validation';
|
} from '@docusaurus/utils-validation';
|
||||||
import type {DocFrontMatter} from '@docusaurus/plugin-content-docs';
|
import type {DocFrontMatter} from '@docusaurus/plugin-content-docs';
|
||||||
|
|
||||||
|
const FrontMatterLastUpdateErrorMessage =
|
||||||
|
'{{#label}} does not look like a valid front matter FileChange object. Please use a FileChange object (with an author and/or date).';
|
||||||
|
|
||||||
// NOTE: we don't add any default value on purpose here
|
// NOTE: we don't add any default value on purpose here
|
||||||
// We don't want default values to magically appear in doc metadata and props
|
// We don't want default values to magically appear in doc metadata and props
|
||||||
// While the user did not provide those values explicitly
|
// While the user did not provide those values explicitly
|
||||||
|
@ -42,6 +45,15 @@ const DocFrontMatterSchema = Joi.object<DocFrontMatter>({
|
||||||
pagination_prev: Joi.string().allow(null),
|
pagination_prev: Joi.string().allow(null),
|
||||||
draft: Joi.boolean(),
|
draft: Joi.boolean(),
|
||||||
...FrontMatterTOCHeadingLevels,
|
...FrontMatterTOCHeadingLevels,
|
||||||
|
last_update: Joi.object({
|
||||||
|
author: Joi.string(),
|
||||||
|
date: Joi.date().raw(),
|
||||||
|
})
|
||||||
|
.or('author', 'date')
|
||||||
|
.messages({
|
||||||
|
'object.missing': FrontMatterLastUpdateErrorMessage,
|
||||||
|
'object.base': FrontMatterLastUpdateErrorMessage,
|
||||||
|
}),
|
||||||
}).unknown();
|
}).unknown();
|
||||||
|
|
||||||
export function validateDocFrontMatter(frontMatter: {
|
export function validateDocFrontMatter(frontMatter: {
|
||||||
|
|
|
@ -23,6 +23,14 @@ declare module '@docusaurus/plugin-content-docs' {
|
||||||
image?: string;
|
image?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type FileChange = {
|
||||||
|
author?: string;
|
||||||
|
/** Date can be any
|
||||||
|
* [parsable date string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse).
|
||||||
|
*/
|
||||||
|
date?: Date | string;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom callback for parsing number prefixes from file/folder names.
|
* Custom callback for parsing number prefixes from file/folder names.
|
||||||
*/
|
*/
|
||||||
|
@ -371,6 +379,8 @@ declare module '@docusaurus/plugin-content-docs' {
|
||||||
pagination_prev?: string | null;
|
pagination_prev?: string | null;
|
||||||
/** Should this doc be excluded from production builds? */
|
/** Should this doc be excluded from production builds? */
|
||||||
draft?: boolean;
|
draft?: boolean;
|
||||||
|
/** Allows overriding the last updated author and/or date. */
|
||||||
|
last_update?: FileChange;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type LastUpdateData = {
|
export type LastUpdateData = {
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
import type {BrokenMarkdownLink, Tag} from '@docusaurus/utils';
|
import type {BrokenMarkdownLink, Tag} from '@docusaurus/utils';
|
||||||
import type {
|
import type {
|
||||||
VersionMetadata,
|
VersionMetadata,
|
||||||
LastUpdateData,
|
|
||||||
LoadedVersion,
|
LoadedVersion,
|
||||||
CategoryGeneratedIndexMetadata,
|
CategoryGeneratedIndexMetadata,
|
||||||
} from '@docusaurus/plugin-content-docs';
|
} from '@docusaurus/plugin-content-docs';
|
||||||
|
@ -19,7 +18,6 @@ export type DocFile = {
|
||||||
filePath: string; // /!\ may be localized
|
filePath: string; // /!\ may be localized
|
||||||
source: string;
|
source: string;
|
||||||
content: string;
|
content: string;
|
||||||
lastUpdate: LastUpdateData;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SourceToPermalink = {
|
export type SourceToPermalink = {
|
||||||
|
|
7
website/_dogfooding/_docs tests/doc-with-last-update.md
Normal file
7
website/_dogfooding/_docs tests/doc-with-last-update.md
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
last_update:
|
||||||
|
author: custom author
|
||||||
|
date: 1/1/2000
|
||||||
|
---
|
||||||
|
|
||||||
|
# Doc With Last Update Front Matter
|
|
@ -22,6 +22,7 @@ const sidebars = {
|
||||||
'test-draft',
|
'test-draft',
|
||||||
'doc-without-sidebar',
|
'doc-without-sidebar',
|
||||||
'doc-with-another-sidebar',
|
'doc-with-another-sidebar',
|
||||||
|
'doc-with-last-update',
|
||||||
{
|
{
|
||||||
type: 'category',
|
type: 'category',
|
||||||
label: 'Tests',
|
label: 'Tests',
|
||||||
|
|
|
@ -30,6 +30,7 @@ const dogfoodingPluginInstances = [
|
||||||
// Using a _ prefix to test against an edge case regarding MDX partials: https://github.com/facebook/docusaurus/discussions/5181#discussioncomment-1018079
|
// Using a _ prefix to test against an edge case regarding MDX partials: https://github.com/facebook/docusaurus/discussions/5181#discussioncomment-1018079
|
||||||
path: '_dogfooding/_docs tests',
|
path: '_dogfooding/_docs tests',
|
||||||
showLastUpdateTime: true,
|
showLastUpdateTime: true,
|
||||||
|
showLastUpdateAuthor: true,
|
||||||
sidebarItemsGenerator(args) {
|
sidebarItemsGenerator(args) {
|
||||||
return args.defaultSidebarItemsGenerator({
|
return args.defaultSidebarItemsGenerator({
|
||||||
...args,
|
...args,
|
||||||
|
|
|
@ -281,6 +281,7 @@ Accepted fields:
|
||||||
| `slug` | `string` | File path | Allows to customize the document url (`/<routeBasePath>/<slug>`). Support multiple patterns: `slug: my-doc`, `slug: /my/path/myDoc`, `slug: /`. |
|
| `slug` | `string` | File path | Allows to customize the document url (`/<routeBasePath>/<slug>`). Support multiple patterns: `slug: my-doc`, `slug: /my/path/myDoc`, `slug: /`. |
|
||||||
| `tags` | `Tag[]` | `undefined` | A list of strings or objects of two string fields `label` and `permalink` to tag to your docs. |
|
| `tags` | `Tag[]` | `undefined` | A list of strings or objects of two string fields `label` and `permalink` to tag to your docs. |
|
||||||
| `draft` | `boolean` | `false` | A boolean flag to indicate that a document is a work-in-progress. Draft documents will only be displayed during development. |
|
| `draft` | `boolean` | `false` | A boolean flag to indicate that a document is a work-in-progress. Draft documents will only be displayed during development. |
|
||||||
|
| `last_update` | `FileChange` | `undefined` | Allows overriding the last updated author and/or date. Date can be any [parsable date string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse). |
|
||||||
|
|
||||||
</APITable>
|
</APITable>
|
||||||
|
|
||||||
|
@ -288,6 +289,10 @@ Accepted fields:
|
||||||
type Tag = string | {label: string; permalink: string};
|
type Tag = string | {label: string; permalink: string};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```ts
|
||||||
|
type FileChange = {date: string; author: string};
|
||||||
|
```
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
```md
|
```md
|
||||||
|
@ -306,6 +311,9 @@ keywords:
|
||||||
- docusaurus
|
- docusaurus
|
||||||
image: https://i.imgur.com/mErPwqL.png
|
image: https://i.imgur.com/mErPwqL.png
|
||||||
slug: /myDoc
|
slug: /myDoc
|
||||||
|
last_update:
|
||||||
|
date: 1/1/2000
|
||||||
|
author: custom author name
|
||||||
---
|
---
|
||||||
|
|
||||||
# Markdown Features
|
# Markdown Features
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue