@docusaurus/plugin-content-blog 2.0.0-beta.2 → 2.0.0-beta.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/authors.d.ts +22 -0
- package/lib/authors.js +122 -0
- package/lib/blogUtils.d.ts +27 -7
- package/lib/blogUtils.js +201 -145
- package/lib/feed.d.ts +15 -0
- package/lib/feed.js +102 -0
- package/lib/frontMatter.d.ts +10 -0
- package/lib/{blogFrontMatter.js → frontMatter.js} +31 -19
- package/lib/index.d.ts +4 -4
- package/lib/index.js +165 -201
- package/lib/markdownLoader.d.ts +3 -6
- package/lib/markdownLoader.js +6 -7
- package/lib/options.d.ts +10 -0
- package/lib/{pluginOptionSchema.js → options.js} +44 -14
- package/lib/remark/footnoteIDFixer.d.ts +14 -0
- package/lib/remark/footnoteIDFixer.js +29 -0
- package/lib/translations.d.ts +10 -0
- package/lib/translations.js +53 -0
- package/lib/types.d.ts +4 -109
- package/package.json +23 -19
- package/src/authors.ts +168 -0
- package/src/blogUtils.ts +306 -204
- package/src/feed.ts +171 -0
- package/src/frontMatter.ts +81 -0
- package/src/index.ts +230 -269
- package/src/markdownLoader.ts +11 -16
- package/src/{pluginOptionSchema.ts → options.ts} +57 -16
- package/src/plugin-content-blog.d.ts +587 -0
- package/src/remark/footnoteIDFixer.ts +29 -0
- package/src/translations.ts +69 -0
- package/src/types.ts +2 -128
- package/index.d.ts +0 -138
- package/lib/.tsbuildinfo +0 -1
- package/lib/blogFrontMatter.d.ts +0 -28
- package/lib/pluginOptionSchema.d.ts +0 -33
- package/src/__tests__/__fixtures__/website/blog/2018-12-14-Happy-First-Birthday-Slash.md +0 -5
- package/src/__tests__/__fixtures__/website/blog/complex-slug.md +0 -7
- package/src/__tests__/__fixtures__/website/blog/date-matter.md +0 -5
- package/src/__tests__/__fixtures__/website/blog/draft.md +0 -6
- package/src/__tests__/__fixtures__/website/blog/heading-as-title.md +0 -5
- package/src/__tests__/__fixtures__/website/blog/simple-slug.md +0 -7
- package/src/__tests__/__fixtures__/website/blog-with-ref/2018-12-14-Happy-First-Birthday-Slash.md +0 -5
- package/src/__tests__/__fixtures__/website/blog-with-ref/post-with-broken-links.md +0 -11
- package/src/__tests__/__fixtures__/website/blog-with-ref/post.md +0 -5
- package/src/__tests__/__fixtures__/website/i18n/en/docusaurus-plugin-content-blog/2018-12-14-Happy-First-Birthday-Slash.md +0 -5
- package/src/__tests__/__fixtures__/website-blog-without-date/blog/no date.md +0 -1
- package/src/__tests__/__snapshots__/generateBlogFeed.test.ts.snap +0 -76
- package/src/__tests__/__snapshots__/linkify.test.ts.snap +0 -24
- package/src/__tests__/__snapshots__/pluginOptionSchema.test.ts.snap +0 -5
- package/src/__tests__/blogFrontMatter.test.ts +0 -317
- package/src/__tests__/generateBlogFeed.test.ts +0 -100
- package/src/__tests__/index.test.ts +0 -336
- package/src/__tests__/linkify.test.ts +0 -93
- package/src/__tests__/pluginOptionSchema.test.ts +0 -150
- package/src/blogFrontMatter.ts +0 -88
- package/tsconfig.json +0 -9
- package/types.d.ts +0 -13
|
@@ -6,14 +6,15 @@
|
|
|
6
6
|
* LICENSE file in the root directory of this source tree.
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.
|
|
9
|
+
exports.validateOptions = exports.DEFAULT_OPTIONS = void 0;
|
|
10
10
|
const utils_validation_1 = require("@docusaurus/utils-validation");
|
|
11
|
+
const utils_1 = require("@docusaurus/utils");
|
|
11
12
|
exports.DEFAULT_OPTIONS = {
|
|
12
|
-
feedOptions: { type: ['rss', 'atom'] },
|
|
13
|
+
feedOptions: { type: ['rss', 'atom'], copyright: '' },
|
|
13
14
|
beforeDefaultRehypePlugins: [],
|
|
14
15
|
beforeDefaultRemarkPlugins: [],
|
|
15
|
-
admonitions:
|
|
16
|
-
truncateMarker: /<!--\s*
|
|
16
|
+
admonitions: true,
|
|
17
|
+
truncateMarker: /<!--\s*truncate\s*-->/,
|
|
17
18
|
rehypePlugins: [],
|
|
18
19
|
remarkPlugins: [],
|
|
19
20
|
showReadingTime: true,
|
|
@@ -21,37 +22,49 @@ exports.DEFAULT_OPTIONS = {
|
|
|
21
22
|
blogTagsListComponent: '@theme/BlogTagsListPage',
|
|
22
23
|
blogPostComponent: '@theme/BlogPostPage',
|
|
23
24
|
blogListComponent: '@theme/BlogListPage',
|
|
25
|
+
blogArchiveComponent: '@theme/BlogArchivePage',
|
|
24
26
|
blogDescription: 'Blog',
|
|
25
27
|
blogTitle: 'Blog',
|
|
26
28
|
blogSidebarCount: 5,
|
|
27
29
|
blogSidebarTitle: 'Recent posts',
|
|
28
30
|
postsPerPage: 10,
|
|
29
|
-
include: ['
|
|
31
|
+
include: ['**/*.{md,mdx}'],
|
|
32
|
+
exclude: utils_1.GlobExcludeDefault,
|
|
30
33
|
routeBasePath: 'blog',
|
|
34
|
+
tagsBasePath: 'tags',
|
|
35
|
+
archiveBasePath: 'archive',
|
|
31
36
|
path: 'blog',
|
|
32
37
|
editLocalizedFiles: false,
|
|
38
|
+
authorsMapPath: 'authors.yml',
|
|
39
|
+
readingTime: ({ content, defaultReadingTime }) => defaultReadingTime({ content }),
|
|
40
|
+
sortPosts: 'descending',
|
|
33
41
|
};
|
|
34
|
-
|
|
42
|
+
const PluginOptionSchema = utils_validation_1.Joi.object({
|
|
35
43
|
path: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.path),
|
|
44
|
+
archiveBasePath: utils_validation_1.Joi.string()
|
|
45
|
+
.default(exports.DEFAULT_OPTIONS.archiveBasePath)
|
|
46
|
+
.allow(null),
|
|
36
47
|
routeBasePath: utils_validation_1.Joi.string()
|
|
37
48
|
// '' not allowed, see https://github.com/facebook/docusaurus/issues/3374
|
|
38
49
|
// .allow('')
|
|
39
50
|
.default(exports.DEFAULT_OPTIONS.routeBasePath),
|
|
51
|
+
tagsBasePath: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.tagsBasePath),
|
|
40
52
|
include: utils_validation_1.Joi.array().items(utils_validation_1.Joi.string()).default(exports.DEFAULT_OPTIONS.include),
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
.min(1)
|
|
53
|
+
exclude: utils_validation_1.Joi.array().items(utils_validation_1.Joi.string()).default(exports.DEFAULT_OPTIONS.exclude),
|
|
54
|
+
postsPerPage: utils_validation_1.Joi.alternatives()
|
|
55
|
+
.try(utils_validation_1.Joi.equal('ALL').required(), utils_validation_1.Joi.number().integer().min(1).required())
|
|
44
56
|
.default(exports.DEFAULT_OPTIONS.postsPerPage),
|
|
45
57
|
blogListComponent: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.blogListComponent),
|
|
46
58
|
blogPostComponent: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.blogPostComponent),
|
|
47
59
|
blogTagsListComponent: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.blogTagsListComponent),
|
|
48
60
|
blogTagsPostsComponent: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.blogTagsPostsComponent),
|
|
61
|
+
blogArchiveComponent: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.blogArchiveComponent),
|
|
49
62
|
blogTitle: utils_validation_1.Joi.string().allow('').default(exports.DEFAULT_OPTIONS.blogTitle),
|
|
50
63
|
blogDescription: utils_validation_1.Joi.string()
|
|
51
64
|
.allow('')
|
|
52
65
|
.default(exports.DEFAULT_OPTIONS.blogDescription),
|
|
53
66
|
blogSidebarCount: utils_validation_1.Joi.alternatives()
|
|
54
|
-
.try(utils_validation_1.Joi.equal('ALL').required(), utils_validation_1.Joi.number().required())
|
|
67
|
+
.try(utils_validation_1.Joi.equal('ALL').required(), utils_validation_1.Joi.number().integer().min(0).required())
|
|
55
68
|
.default(exports.DEFAULT_OPTIONS.blogSidebarCount),
|
|
56
69
|
blogSidebarTitle: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.blogSidebarTitle),
|
|
57
70
|
showReadingTime: utils_validation_1.Joi.bool().default(exports.DEFAULT_OPTIONS.showReadingTime),
|
|
@@ -65,14 +78,31 @@ exports.PluginOptionSchema = utils_validation_1.Joi.object({
|
|
|
65
78
|
beforeDefaultRehypePlugins: utils_validation_1.RehypePluginsSchema.default(exports.DEFAULT_OPTIONS.beforeDefaultRehypePlugins),
|
|
66
79
|
feedOptions: utils_validation_1.Joi.object({
|
|
67
80
|
type: utils_validation_1.Joi.alternatives()
|
|
68
|
-
.try(utils_validation_1.Joi.array().items(utils_validation_1.Joi.string()), utils_validation_1.Joi.alternatives().conditional(utils_validation_1.Joi.string().equal('all', 'rss', 'atom'), {
|
|
69
|
-
then: utils_validation_1.Joi.custom((val) => val === 'all' ? ['rss', 'atom'] : [val]),
|
|
81
|
+
.try(utils_validation_1.Joi.array().items(utils_validation_1.Joi.string().equal('rss', 'atom', 'json')), utils_validation_1.Joi.alternatives().conditional(utils_validation_1.Joi.string().equal('all', 'rss', 'atom', 'json'), {
|
|
82
|
+
then: utils_validation_1.Joi.custom((val) => val === 'all' ? ['rss', 'atom', 'json'] : [val]),
|
|
70
83
|
}))
|
|
71
84
|
.allow(null)
|
|
72
85
|
.default(exports.DEFAULT_OPTIONS.feedOptions.type),
|
|
73
86
|
title: utils_validation_1.Joi.string().allow(''),
|
|
74
87
|
description: utils_validation_1.Joi.string().allow(''),
|
|
75
|
-
|
|
88
|
+
// Only add default value when user actually wants a feed (type is not null)
|
|
89
|
+
copyright: utils_validation_1.Joi.when('type', {
|
|
90
|
+
is: utils_validation_1.Joi.any().valid(null),
|
|
91
|
+
then: utils_validation_1.Joi.string().optional(),
|
|
92
|
+
otherwise: utils_validation_1.Joi.string()
|
|
93
|
+
.allow('')
|
|
94
|
+
.default(exports.DEFAULT_OPTIONS.feedOptions.copyright),
|
|
95
|
+
}),
|
|
76
96
|
language: utils_validation_1.Joi.string(),
|
|
77
97
|
}).default(exports.DEFAULT_OPTIONS.feedOptions),
|
|
78
|
-
|
|
98
|
+
authorsMapPath: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.authorsMapPath),
|
|
99
|
+
readingTime: utils_validation_1.Joi.function().default(() => exports.DEFAULT_OPTIONS.readingTime),
|
|
100
|
+
sortPosts: utils_validation_1.Joi.string()
|
|
101
|
+
.valid('descending', 'ascending')
|
|
102
|
+
.default(exports.DEFAULT_OPTIONS.sortPosts),
|
|
103
|
+
}).default(exports.DEFAULT_OPTIONS);
|
|
104
|
+
function validateOptions({ validate, options, }) {
|
|
105
|
+
const validatedOptions = validate(PluginOptionSchema, options);
|
|
106
|
+
return validatedOptions;
|
|
107
|
+
}
|
|
108
|
+
exports.validateOptions = validateOptions;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
import type { Transformer } from 'unified';
|
|
8
|
+
/**
|
|
9
|
+
* In the blog list view, each post will be compiled separately. However, they
|
|
10
|
+
* may use the same footnote IDs. This leads to duplicated DOM IDs and inability
|
|
11
|
+
* to navigate to footnote references. This plugin fixes it by appending a
|
|
12
|
+
* unique hash to each reference/definition.
|
|
13
|
+
*/
|
|
14
|
+
export default function plugin(): Transformer;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
const tslib_1 = require("tslib");
|
|
10
|
+
const unist_util_visit_1 = tslib_1.__importDefault(require("unist-util-visit"));
|
|
11
|
+
const utils_1 = require("@docusaurus/utils");
|
|
12
|
+
/**
|
|
13
|
+
* In the blog list view, each post will be compiled separately. However, they
|
|
14
|
+
* may use the same footnote IDs. This leads to duplicated DOM IDs and inability
|
|
15
|
+
* to navigate to footnote references. This plugin fixes it by appending a
|
|
16
|
+
* unique hash to each reference/definition.
|
|
17
|
+
*/
|
|
18
|
+
function plugin() {
|
|
19
|
+
return (root, vfile) => {
|
|
20
|
+
const suffix = `-${(0, utils_1.simpleHash)(vfile.path, 6)}`;
|
|
21
|
+
(0, unist_util_visit_1.default)(root, 'footnoteReference', (node) => {
|
|
22
|
+
node.identifier += suffix;
|
|
23
|
+
});
|
|
24
|
+
(0, unist_util_visit_1.default)(root, 'footnoteDefinition', (node) => {
|
|
25
|
+
node.identifier += suffix;
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
exports.default = plugin;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
import type { TranslationFile } from '@docusaurus/types';
|
|
8
|
+
import type { PluginOptions, BlogContent } from '@docusaurus/plugin-content-blog';
|
|
9
|
+
export declare function getTranslationFiles(options: PluginOptions): TranslationFile[];
|
|
10
|
+
export declare function translateContent(content: BlogContent, translationFiles: TranslationFile[]): BlogContent;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.translateContent = exports.getTranslationFiles = void 0;
|
|
10
|
+
function translateListPage(blogListPaginated, translations) {
|
|
11
|
+
return blogListPaginated.map((page) => {
|
|
12
|
+
const { items, metadata } = page;
|
|
13
|
+
return {
|
|
14
|
+
items,
|
|
15
|
+
metadata: {
|
|
16
|
+
...metadata,
|
|
17
|
+
blogTitle: translations.title?.message ?? page.metadata.blogTitle,
|
|
18
|
+
blogDescription: translations.description?.message ?? page.metadata.blogDescription,
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
function getTranslationFiles(options) {
|
|
24
|
+
return [
|
|
25
|
+
{
|
|
26
|
+
path: 'options',
|
|
27
|
+
content: {
|
|
28
|
+
title: {
|
|
29
|
+
message: options.blogTitle,
|
|
30
|
+
description: 'The title for the blog used in SEO',
|
|
31
|
+
},
|
|
32
|
+
description: {
|
|
33
|
+
message: options.blogDescription,
|
|
34
|
+
description: 'The description for the blog used in SEO',
|
|
35
|
+
},
|
|
36
|
+
'sidebar.title': {
|
|
37
|
+
message: options.blogSidebarTitle,
|
|
38
|
+
description: 'The label for the left sidebar',
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
];
|
|
43
|
+
}
|
|
44
|
+
exports.getTranslationFiles = getTranslationFiles;
|
|
45
|
+
function translateContent(content, translationFiles) {
|
|
46
|
+
const { content: optionsTranslations } = translationFiles[0];
|
|
47
|
+
return {
|
|
48
|
+
...content,
|
|
49
|
+
blogSidebarTitle: optionsTranslations['sidebar.title']?.message ?? content.blogSidebarTitle,
|
|
50
|
+
blogListPaginated: translateListPage(content.blogListPaginated, optionsTranslations),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
exports.translateContent = translateContent;
|
package/lib/types.d.ts
CHANGED
|
@@ -4,120 +4,15 @@
|
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
|
-
import type {
|
|
8
|
-
import { BrokenMarkdownLink, ContentPaths } from '@docusaurus/utils/lib/markdownLinks';
|
|
7
|
+
import type { BrokenMarkdownLink, ContentPaths } from '@docusaurus/utils';
|
|
9
8
|
export declare type BlogContentPaths = ContentPaths;
|
|
10
|
-
export interface BlogContent {
|
|
11
|
-
blogPosts: BlogPost[];
|
|
12
|
-
blogListPaginated: BlogPaginated[];
|
|
13
|
-
blogTags: BlogTags;
|
|
14
|
-
blogTagsListPath: string | null;
|
|
15
|
-
}
|
|
16
|
-
export interface DateLink {
|
|
17
|
-
date: Date;
|
|
18
|
-
link: string;
|
|
19
|
-
}
|
|
20
|
-
export declare type FeedType = 'rss' | 'atom';
|
|
21
|
-
export declare type EditUrlFunction = (editUrlParams: {
|
|
22
|
-
blogDirPath: string;
|
|
23
|
-
blogPath: string;
|
|
24
|
-
permalink: string;
|
|
25
|
-
locale: string;
|
|
26
|
-
}) => string | undefined;
|
|
27
|
-
export interface PluginOptions extends RemarkAndRehypePluginOptions {
|
|
28
|
-
id?: string;
|
|
29
|
-
path: string;
|
|
30
|
-
routeBasePath: string;
|
|
31
|
-
include: string[];
|
|
32
|
-
postsPerPage: number;
|
|
33
|
-
blogListComponent: string;
|
|
34
|
-
blogPostComponent: string;
|
|
35
|
-
blogTagsListComponent: string;
|
|
36
|
-
blogTagsPostsComponent: string;
|
|
37
|
-
blogTitle: string;
|
|
38
|
-
blogDescription: string;
|
|
39
|
-
blogSidebarCount: number | 'ALL';
|
|
40
|
-
blogSidebarTitle: string;
|
|
41
|
-
truncateMarker: RegExp;
|
|
42
|
-
showReadingTime: boolean;
|
|
43
|
-
feedOptions: {
|
|
44
|
-
type?: [FeedType] | null;
|
|
45
|
-
title?: string;
|
|
46
|
-
description?: string;
|
|
47
|
-
copyright: string;
|
|
48
|
-
language?: string;
|
|
49
|
-
};
|
|
50
|
-
editUrl?: string | EditUrlFunction;
|
|
51
|
-
editLocalizedFiles?: boolean;
|
|
52
|
-
admonitions: Record<string, unknown>;
|
|
53
|
-
}
|
|
54
|
-
export interface BlogTags {
|
|
55
|
-
[key: string]: BlogTag;
|
|
56
|
-
}
|
|
57
|
-
export interface BlogTag {
|
|
58
|
-
name: string;
|
|
59
|
-
items: string[];
|
|
60
|
-
permalink: string;
|
|
61
|
-
}
|
|
62
|
-
export interface BlogPost {
|
|
63
|
-
id: string;
|
|
64
|
-
metadata: MetaData;
|
|
65
|
-
}
|
|
66
|
-
export interface BlogPaginatedMetadata {
|
|
67
|
-
permalink: string;
|
|
68
|
-
page: number;
|
|
69
|
-
postsPerPage: number;
|
|
70
|
-
totalPages: number;
|
|
71
|
-
totalCount: number;
|
|
72
|
-
previousPage: string | null;
|
|
73
|
-
nextPage: string | null;
|
|
74
|
-
blogTitle: string;
|
|
75
|
-
blogDescription: string;
|
|
76
|
-
}
|
|
77
|
-
export interface BlogPaginated {
|
|
78
|
-
metadata: BlogPaginatedMetadata;
|
|
79
|
-
items: string[];
|
|
80
|
-
}
|
|
81
|
-
export interface MetaData {
|
|
82
|
-
permalink: string;
|
|
83
|
-
source: string;
|
|
84
|
-
description: string;
|
|
85
|
-
date: Date;
|
|
86
|
-
formattedDate: string;
|
|
87
|
-
tags: (Tag | string)[];
|
|
88
|
-
title: string;
|
|
89
|
-
readingTime?: number;
|
|
90
|
-
prevItem?: Paginator;
|
|
91
|
-
nextItem?: Paginator;
|
|
92
|
-
truncated: boolean;
|
|
93
|
-
editUrl?: string;
|
|
94
|
-
}
|
|
95
|
-
export interface Paginator {
|
|
96
|
-
title: string;
|
|
97
|
-
permalink: string;
|
|
98
|
-
}
|
|
99
|
-
export interface Tag {
|
|
100
|
-
label: string;
|
|
101
|
-
permalink: string;
|
|
102
|
-
}
|
|
103
|
-
export interface BlogItemsToMetadata {
|
|
104
|
-
[key: string]: MetaData;
|
|
105
|
-
}
|
|
106
|
-
export interface TagsModule {
|
|
107
|
-
[key: string]: TagModule;
|
|
108
|
-
}
|
|
109
|
-
export interface TagModule {
|
|
110
|
-
allTagsPath: string;
|
|
111
|
-
slug: string;
|
|
112
|
-
name: string;
|
|
113
|
-
count: number;
|
|
114
|
-
permalink: string;
|
|
115
|
-
}
|
|
116
9
|
export declare type BlogBrokenMarkdownLink = BrokenMarkdownLink<BlogContentPaths>;
|
|
117
10
|
export declare type BlogMarkdownLoaderOptions = {
|
|
118
11
|
siteDir: string;
|
|
119
12
|
contentPaths: BlogContentPaths;
|
|
120
13
|
truncateMarker: RegExp;
|
|
121
|
-
sourceToPermalink:
|
|
14
|
+
sourceToPermalink: {
|
|
15
|
+
[aliasedPath: string]: string;
|
|
16
|
+
};
|
|
122
17
|
onBrokenMarkdownLink: (brokenMarkdownLink: BlogBrokenMarkdownLink) => void;
|
|
123
18
|
};
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@docusaurus/plugin-content-blog",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.22",
|
|
4
4
|
"description": "Blog plugin for Docusaurus.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
|
-
"types": "
|
|
6
|
+
"types": "src/plugin-content-blog.d.ts",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"build": "tsc",
|
|
9
9
|
"watch": "tsc --watch"
|
|
@@ -18,29 +18,33 @@
|
|
|
18
18
|
},
|
|
19
19
|
"license": "MIT",
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@docusaurus/core": "2.0.0-beta.
|
|
22
|
-
"@docusaurus/
|
|
23
|
-
"@docusaurus/
|
|
24
|
-
"@docusaurus/
|
|
25
|
-
"@docusaurus/utils
|
|
26
|
-
"
|
|
27
|
-
"
|
|
21
|
+
"@docusaurus/core": "2.0.0-beta.22",
|
|
22
|
+
"@docusaurus/logger": "2.0.0-beta.22",
|
|
23
|
+
"@docusaurus/mdx-loader": "2.0.0-beta.22",
|
|
24
|
+
"@docusaurus/types": "2.0.0-beta.22",
|
|
25
|
+
"@docusaurus/utils": "2.0.0-beta.22",
|
|
26
|
+
"@docusaurus/utils-common": "2.0.0-beta.22",
|
|
27
|
+
"@docusaurus/utils-validation": "2.0.0-beta.22",
|
|
28
|
+
"cheerio": "^1.0.0-rc.12",
|
|
28
29
|
"feed": "^4.2.2",
|
|
29
|
-
"fs-extra": "^10.
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
|
|
30
|
+
"fs-extra": "^10.1.0",
|
|
31
|
+
"lodash": "^4.17.21",
|
|
32
|
+
"reading-time": "^1.5.0",
|
|
33
|
+
"tslib": "^2.4.0",
|
|
34
|
+
"unist-util-visit": "^2.0.3",
|
|
35
|
+
"utility-types": "^3.10.0",
|
|
36
|
+
"webpack": "^5.73.0"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@docusaurus/types": "2.0.0-beta.21",
|
|
40
|
+
"escape-string-regexp": "^4.0.0"
|
|
37
41
|
},
|
|
38
42
|
"peerDependencies": {
|
|
39
43
|
"react": "^16.8.4 || ^17.0.0",
|
|
40
44
|
"react-dom": "^16.8.4 || ^17.0.0"
|
|
41
45
|
},
|
|
42
46
|
"engines": {
|
|
43
|
-
"node": ">=
|
|
47
|
+
"node": ">=16.14"
|
|
44
48
|
},
|
|
45
|
-
"gitHead": "
|
|
49
|
+
"gitHead": "daf9e462c4eebb7ac26a940932311f987e768f87"
|
|
46
50
|
}
|
package/src/authors.ts
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {getDataFileData} from '@docusaurus/utils';
|
|
9
|
+
import {Joi, URISchema} from '@docusaurus/utils-validation';
|
|
10
|
+
import type {BlogContentPaths} from './types';
|
|
11
|
+
import type {
|
|
12
|
+
Author,
|
|
13
|
+
BlogPostFrontMatter,
|
|
14
|
+
BlogPostFrontMatterAuthor,
|
|
15
|
+
BlogPostFrontMatterAuthors,
|
|
16
|
+
} from '@docusaurus/plugin-content-blog';
|
|
17
|
+
|
|
18
|
+
export type AuthorsMap = {[authorKey: string]: Author};
|
|
19
|
+
|
|
20
|
+
const AuthorsMapSchema = Joi.object<AuthorsMap>()
|
|
21
|
+
.pattern(
|
|
22
|
+
Joi.string(),
|
|
23
|
+
Joi.object({
|
|
24
|
+
name: Joi.string(),
|
|
25
|
+
url: URISchema,
|
|
26
|
+
imageURL: URISchema,
|
|
27
|
+
title: Joi.string(),
|
|
28
|
+
email: Joi.string(),
|
|
29
|
+
})
|
|
30
|
+
.rename('image_url', 'imageURL')
|
|
31
|
+
.or('name', 'imageURL')
|
|
32
|
+
.unknown()
|
|
33
|
+
.required()
|
|
34
|
+
.messages({
|
|
35
|
+
'object.base':
|
|
36
|
+
'{#label} should be an author object containing properties like name, title, and imageURL.',
|
|
37
|
+
'any.required':
|
|
38
|
+
'{#label} cannot be undefined. It should be an author object containing properties like name, title, and imageURL.',
|
|
39
|
+
}),
|
|
40
|
+
)
|
|
41
|
+
.messages({
|
|
42
|
+
'object.base':
|
|
43
|
+
"The authors map file should contain an object where each entry contains an author key and the corresponding author's data.",
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
export function validateAuthorsMap(content: unknown): AuthorsMap {
|
|
47
|
+
const {error, value} = AuthorsMapSchema.validate(content);
|
|
48
|
+
if (error) {
|
|
49
|
+
throw error;
|
|
50
|
+
}
|
|
51
|
+
return value;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export async function getAuthorsMap(params: {
|
|
55
|
+
authorsMapPath: string;
|
|
56
|
+
contentPaths: BlogContentPaths;
|
|
57
|
+
}): Promise<AuthorsMap | undefined> {
|
|
58
|
+
return getDataFileData(
|
|
59
|
+
{
|
|
60
|
+
filePath: params.authorsMapPath,
|
|
61
|
+
contentPaths: params.contentPaths,
|
|
62
|
+
fileType: 'authors map',
|
|
63
|
+
},
|
|
64
|
+
validateAuthorsMap,
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
type AuthorsParam = {
|
|
69
|
+
frontMatter: BlogPostFrontMatter;
|
|
70
|
+
authorsMap: AuthorsMap | undefined;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
// Legacy v1/early-v2 front matter fields
|
|
74
|
+
// We may want to deprecate those in favor of using only frontMatter.authors
|
|
75
|
+
function getFrontMatterAuthorLegacy(
|
|
76
|
+
frontMatter: BlogPostFrontMatter,
|
|
77
|
+
): Author | undefined {
|
|
78
|
+
const name = frontMatter.author;
|
|
79
|
+
const title = frontMatter.author_title ?? frontMatter.authorTitle;
|
|
80
|
+
const url = frontMatter.author_url ?? frontMatter.authorURL;
|
|
81
|
+
const imageURL = frontMatter.author_image_url ?? frontMatter.authorImageURL;
|
|
82
|
+
|
|
83
|
+
if (name || title || url || imageURL) {
|
|
84
|
+
return {
|
|
85
|
+
name,
|
|
86
|
+
title,
|
|
87
|
+
url,
|
|
88
|
+
imageURL,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function normalizeFrontMatterAuthors(
|
|
96
|
+
frontMatterAuthors: BlogPostFrontMatterAuthors = [],
|
|
97
|
+
): BlogPostFrontMatterAuthor[] {
|
|
98
|
+
function normalizeAuthor(
|
|
99
|
+
authorInput: string | Author,
|
|
100
|
+
): BlogPostFrontMatterAuthor {
|
|
101
|
+
if (typeof authorInput === 'string') {
|
|
102
|
+
// Technically, we could allow users to provide an author's name here, but
|
|
103
|
+
// we only support keys, otherwise, a typo in a key would fallback to
|
|
104
|
+
// becoming a name and may end up unnoticed
|
|
105
|
+
return {key: authorInput};
|
|
106
|
+
}
|
|
107
|
+
return authorInput;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return Array.isArray(frontMatterAuthors)
|
|
111
|
+
? frontMatterAuthors.map(normalizeAuthor)
|
|
112
|
+
: [normalizeAuthor(frontMatterAuthors)];
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function getFrontMatterAuthors(params: AuthorsParam): Author[] {
|
|
116
|
+
const {authorsMap} = params;
|
|
117
|
+
const frontMatterAuthors = normalizeFrontMatterAuthors(
|
|
118
|
+
params.frontMatter.authors,
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
function getAuthorsMapAuthor(key: string | undefined): Author | undefined {
|
|
122
|
+
if (key) {
|
|
123
|
+
if (!authorsMap || Object.keys(authorsMap).length === 0) {
|
|
124
|
+
throw new Error(`Can't reference blog post authors by a key (such as '${key}') because no authors map file could be loaded.
|
|
125
|
+
Please double-check your blog plugin config (in particular 'authorsMapPath'), ensure the file exists at the configured path, is not empty, and is valid!`);
|
|
126
|
+
}
|
|
127
|
+
const author = authorsMap[key];
|
|
128
|
+
if (!author) {
|
|
129
|
+
throw Error(`Blog author with key "${key}" not found in the authors map file.
|
|
130
|
+
Valid author keys are:
|
|
131
|
+
${Object.keys(authorsMap)
|
|
132
|
+
.map((validKey) => `- ${validKey}`)
|
|
133
|
+
.join('\n')}`);
|
|
134
|
+
}
|
|
135
|
+
return author;
|
|
136
|
+
}
|
|
137
|
+
return undefined;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function toAuthor(frontMatterAuthor: BlogPostFrontMatterAuthor): Author {
|
|
141
|
+
return {
|
|
142
|
+
// Author def from authorsMap can be locally overridden by front matter
|
|
143
|
+
...getAuthorsMapAuthor(frontMatterAuthor.key),
|
|
144
|
+
...frontMatterAuthor,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return frontMatterAuthors.map(toAuthor);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export function getBlogPostAuthors(params: AuthorsParam): Author[] {
|
|
152
|
+
const authorLegacy = getFrontMatterAuthorLegacy(params.frontMatter);
|
|
153
|
+
const authors = getFrontMatterAuthors(params);
|
|
154
|
+
|
|
155
|
+
if (authorLegacy) {
|
|
156
|
+
// Technically, we could allow mixing legacy/authors front matter, but do we
|
|
157
|
+
// really want to?
|
|
158
|
+
if (authors.length > 0) {
|
|
159
|
+
throw new Error(
|
|
160
|
+
`To declare blog post authors, use the 'authors' front matter in priority.
|
|
161
|
+
Don't mix 'authors' with other existing 'author_*' front matter. Choose one or the other, not both at the same time.`,
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
return [authorLegacy];
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return authors;
|
|
168
|
+
}
|