@docusaurus/plugin-content-blog 0.0.0-6010 → 0.0.0-6014
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 +9 -10
- package/lib/authors.js +41 -78
- package/lib/authorsMap.d.ts +23 -0
- package/lib/authorsMap.js +116 -0
- package/lib/blogUtils.d.ts +2 -2
- package/lib/blogUtils.js +2 -6
- package/lib/index.js +15 -2
- package/lib/options.js +8 -0
- package/lib/props.d.ts +5 -1
- package/lib/props.js +7 -0
- package/lib/routes.js +75 -2
- package/package.json +10 -10
- package/src/authors.ts +57 -111
- package/src/authorsMap.ts +171 -0
- package/src/blogUtils.ts +4 -7
- package/src/index.ts +23 -1
- package/src/options.ts +12 -0
- package/src/plugin-content-blog.d.ts +90 -12
- package/src/props.ts +15 -0
- package/src/routes.ts +97 -2
package/src/authors.ts
CHANGED
|
@@ -5,83 +5,16 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import
|
|
9
|
-
import {
|
|
10
|
-
import {Joi, URISchema} from '@docusaurus/utils-validation';
|
|
11
|
-
import {AuthorSocialsSchema, normalizeSocials} from './authorsSocials';
|
|
12
|
-
import type {BlogContentPaths} from './types';
|
|
8
|
+
import _ from 'lodash';
|
|
9
|
+
import {normalizeUrl} from '@docusaurus/utils';
|
|
13
10
|
import type {
|
|
14
11
|
Author,
|
|
12
|
+
AuthorsMap,
|
|
13
|
+
BlogPost,
|
|
15
14
|
BlogPostFrontMatter,
|
|
16
15
|
BlogPostFrontMatterAuthor,
|
|
17
|
-
BlogPostFrontMatterAuthors,
|
|
18
16
|
} from '@docusaurus/plugin-content-blog';
|
|
19
17
|
|
|
20
|
-
export type AuthorsMap = {[authorKey: string]: Author};
|
|
21
|
-
|
|
22
|
-
const AuthorsMapSchema = Joi.object<AuthorsMap>()
|
|
23
|
-
.pattern(
|
|
24
|
-
Joi.string(),
|
|
25
|
-
Joi.object<Author>({
|
|
26
|
-
name: Joi.string(),
|
|
27
|
-
url: URISchema,
|
|
28
|
-
imageURL: URISchema,
|
|
29
|
-
title: Joi.string(),
|
|
30
|
-
email: Joi.string(),
|
|
31
|
-
socials: AuthorSocialsSchema,
|
|
32
|
-
})
|
|
33
|
-
.rename('image_url', 'imageURL')
|
|
34
|
-
.or('name', 'imageURL')
|
|
35
|
-
.unknown()
|
|
36
|
-
.required()
|
|
37
|
-
.messages({
|
|
38
|
-
'object.base':
|
|
39
|
-
'{#label} should be an author object containing properties like name, title, and imageURL.',
|
|
40
|
-
'any.required':
|
|
41
|
-
'{#label} cannot be undefined. It should be an author object containing properties like name, title, and imageURL.',
|
|
42
|
-
}),
|
|
43
|
-
)
|
|
44
|
-
.messages({
|
|
45
|
-
'object.base':
|
|
46
|
-
"The authors map file should contain an object where each entry contains an author key and the corresponding author's data.",
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
export function validateAuthorsMap(content: unknown): AuthorsMap {
|
|
50
|
-
const {error, value} = AuthorsMapSchema.validate(content);
|
|
51
|
-
if (error) {
|
|
52
|
-
throw error;
|
|
53
|
-
}
|
|
54
|
-
return value;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function normalizeAuthor(author: Author): Author {
|
|
58
|
-
return {
|
|
59
|
-
...author,
|
|
60
|
-
socials: author.socials ? normalizeSocials(author.socials) : undefined,
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function normalizeAuthorsMap(authorsMap: AuthorsMap): AuthorsMap {
|
|
65
|
-
return _.mapValues(authorsMap, normalizeAuthor);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export async function getAuthorsMap(params: {
|
|
69
|
-
authorsMapPath: string;
|
|
70
|
-
contentPaths: BlogContentPaths;
|
|
71
|
-
}): Promise<AuthorsMap | undefined> {
|
|
72
|
-
const authorsMap = await getDataFileData(
|
|
73
|
-
{
|
|
74
|
-
filePath: params.authorsMapPath,
|
|
75
|
-
contentPaths: params.contentPaths,
|
|
76
|
-
fileType: 'authors map',
|
|
77
|
-
},
|
|
78
|
-
// TODO annoying to test: tightly coupled FS reads + validation...
|
|
79
|
-
validateAuthorsMap,
|
|
80
|
-
);
|
|
81
|
-
|
|
82
|
-
return authorsMap ? normalizeAuthorsMap(authorsMap) : undefined;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
18
|
type AuthorsParam = {
|
|
86
19
|
frontMatter: BlogPostFrontMatter;
|
|
87
20
|
authorsMap: AuthorsMap | undefined;
|
|
@@ -102,6 +35,7 @@ function normalizeImageUrl({
|
|
|
102
35
|
|
|
103
36
|
// Legacy v1/early-v2 front matter fields
|
|
104
37
|
// We may want to deprecate those in favor of using only frontMatter.authors
|
|
38
|
+
// TODO Docusaurus v4: remove this legacy front matter
|
|
105
39
|
function getFrontMatterAuthorLegacy({
|
|
106
40
|
baseUrl,
|
|
107
41
|
frontMatter,
|
|
@@ -123,37 +57,40 @@ function getFrontMatterAuthorLegacy({
|
|
|
123
57
|
title,
|
|
124
58
|
url,
|
|
125
59
|
imageURL,
|
|
60
|
+
// legacy front matter authors do not have an author key/page
|
|
61
|
+
key: null,
|
|
62
|
+
page: null,
|
|
126
63
|
};
|
|
127
64
|
}
|
|
128
65
|
|
|
129
66
|
return undefined;
|
|
130
67
|
}
|
|
131
68
|
|
|
132
|
-
function
|
|
133
|
-
|
|
134
|
-
)
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
// Technically, we could allow users to provide an author's name here, but
|
|
140
|
-
// we only support keys, otherwise, a typo in a key would fallback to
|
|
141
|
-
// becoming a name and may end up unnoticed
|
|
142
|
-
return {key: authorInput};
|
|
69
|
+
function getFrontMatterAuthors(params: AuthorsParam): Author[] {
|
|
70
|
+
const {authorsMap, frontMatter, baseUrl} = params;
|
|
71
|
+
return normalizeFrontMatterAuthors().map(toAuthor);
|
|
72
|
+
|
|
73
|
+
function normalizeFrontMatterAuthors(): BlogPostFrontMatterAuthor[] {
|
|
74
|
+
if (frontMatter.authors === undefined) {
|
|
75
|
+
return [];
|
|
143
76
|
}
|
|
144
|
-
return authorInput;
|
|
145
|
-
}
|
|
146
77
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
:
|
|
150
|
-
|
|
78
|
+
function normalizeAuthor(
|
|
79
|
+
authorInput: string | BlogPostFrontMatterAuthor,
|
|
80
|
+
): BlogPostFrontMatterAuthor {
|
|
81
|
+
if (typeof authorInput === 'string') {
|
|
82
|
+
// We could allow users to provide an author's name here, but we only
|
|
83
|
+
// support keys, otherwise, a typo in a key would fall back to
|
|
84
|
+
// becoming a name and may end up unnoticed
|
|
85
|
+
return {key: authorInput};
|
|
86
|
+
}
|
|
87
|
+
return authorInput;
|
|
88
|
+
}
|
|
151
89
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
);
|
|
90
|
+
return Array.isArray(frontMatter.authors)
|
|
91
|
+
? frontMatter.authors.map(normalizeAuthor)
|
|
92
|
+
: [normalizeAuthor(frontMatter.authors)];
|
|
93
|
+
}
|
|
157
94
|
|
|
158
95
|
function getAuthorsMapAuthor(key: string | undefined): Author | undefined {
|
|
159
96
|
if (key) {
|
|
@@ -175,36 +112,29 @@ ${Object.keys(authorsMap)
|
|
|
175
112
|
}
|
|
176
113
|
|
|
177
114
|
function toAuthor(frontMatterAuthor: BlogPostFrontMatterAuthor): Author {
|
|
178
|
-
|
|
115
|
+
const author = {
|
|
179
116
|
// Author def from authorsMap can be locally overridden by front matter
|
|
180
117
|
...getAuthorsMapAuthor(frontMatterAuthor.key),
|
|
181
118
|
...frontMatterAuthor,
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
return frontMatterAuthors.map(toAuthor);
|
|
186
|
-
}
|
|
119
|
+
};
|
|
187
120
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
}));
|
|
121
|
+
return {
|
|
122
|
+
...author,
|
|
123
|
+
key: author.key ?? null,
|
|
124
|
+
page: author.page ?? null,
|
|
125
|
+
imageURL: normalizeImageUrl({imageURL: author.imageURL, baseUrl}),
|
|
126
|
+
};
|
|
127
|
+
}
|
|
196
128
|
}
|
|
197
129
|
|
|
198
130
|
export function getBlogPostAuthors(params: AuthorsParam): Author[] {
|
|
199
131
|
const authorLegacy = getFrontMatterAuthorLegacy(params);
|
|
200
132
|
const authors = getFrontMatterAuthors(params);
|
|
201
133
|
|
|
202
|
-
const updatedAuthors = fixAuthorImageBaseURL(authors, params);
|
|
203
|
-
|
|
204
134
|
if (authorLegacy) {
|
|
205
135
|
// Technically, we could allow mixing legacy/authors front matter, but do we
|
|
206
136
|
// really want to?
|
|
207
|
-
if (
|
|
137
|
+
if (authors.length > 0) {
|
|
208
138
|
throw new Error(
|
|
209
139
|
`To declare blog post authors, use the 'authors' front matter in priority.
|
|
210
140
|
Don't mix 'authors' with other existing 'author_*' front matter. Choose one or the other, not both at the same time.`,
|
|
@@ -213,5 +143,21 @@ Don't mix 'authors' with other existing 'author_*' front matter. Choose one or t
|
|
|
213
143
|
return [authorLegacy];
|
|
214
144
|
}
|
|
215
145
|
|
|
216
|
-
return
|
|
146
|
+
return authors;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Group blog posts by author key
|
|
151
|
+
* Blog posts with only inline authors are ignored
|
|
152
|
+
*/
|
|
153
|
+
export function groupBlogPostsByAuthorKey({
|
|
154
|
+
blogPosts,
|
|
155
|
+
authorsMap,
|
|
156
|
+
}: {
|
|
157
|
+
blogPosts: BlogPost[];
|
|
158
|
+
authorsMap: AuthorsMap | undefined;
|
|
159
|
+
}): Record<string, BlogPost[]> {
|
|
160
|
+
return _.mapValues(authorsMap, (author, key) =>
|
|
161
|
+
blogPosts.filter((p) => p.metadata.authors.some((a) => a.key === key)),
|
|
162
|
+
);
|
|
217
163
|
}
|
|
@@ -0,0 +1,171 @@
|
|
|
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 _ from 'lodash';
|
|
9
|
+
import {readDataFile, normalizeUrl} from '@docusaurus/utils';
|
|
10
|
+
import {Joi, URISchema} from '@docusaurus/utils-validation';
|
|
11
|
+
import {AuthorSocialsSchema, normalizeSocials} from './authorsSocials';
|
|
12
|
+
import type {BlogContentPaths} from './types';
|
|
13
|
+
import type {
|
|
14
|
+
Author,
|
|
15
|
+
AuthorAttributes,
|
|
16
|
+
AuthorPage,
|
|
17
|
+
AuthorsMap,
|
|
18
|
+
} from '@docusaurus/plugin-content-blog';
|
|
19
|
+
|
|
20
|
+
type AuthorInput = AuthorAttributes & {
|
|
21
|
+
page?: boolean | AuthorPage;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export type AuthorsMapInput = {[authorKey: string]: AuthorInput};
|
|
25
|
+
|
|
26
|
+
const AuthorPageSchema = Joi.object<AuthorPage>({
|
|
27
|
+
permalink: Joi.string().required(),
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const AuthorsMapInputSchema = Joi.object<AuthorsMapInput>()
|
|
31
|
+
.pattern(
|
|
32
|
+
Joi.string(),
|
|
33
|
+
Joi.object({
|
|
34
|
+
name: Joi.string(),
|
|
35
|
+
url: URISchema,
|
|
36
|
+
imageURL: URISchema,
|
|
37
|
+
title: Joi.string(),
|
|
38
|
+
email: Joi.string(),
|
|
39
|
+
page: Joi.alternatives(Joi.bool(), AuthorPageSchema),
|
|
40
|
+
socials: AuthorSocialsSchema,
|
|
41
|
+
description: Joi.string(),
|
|
42
|
+
})
|
|
43
|
+
.rename('image_url', 'imageURL')
|
|
44
|
+
.or('name', 'imageURL')
|
|
45
|
+
.unknown()
|
|
46
|
+
.required()
|
|
47
|
+
.messages({
|
|
48
|
+
'object.base':
|
|
49
|
+
'{#label} should be an author object containing properties like name, title, and imageURL.',
|
|
50
|
+
'any.required':
|
|
51
|
+
'{#label} cannot be undefined. It should be an author object containing properties like name, title, and imageURL.',
|
|
52
|
+
}),
|
|
53
|
+
)
|
|
54
|
+
.messages({
|
|
55
|
+
'object.base':
|
|
56
|
+
"The authors map file should contain an object where each entry contains an author key and the corresponding author's data.",
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
export function checkAuthorsMapPermalinkCollisions(
|
|
60
|
+
authorsMap: AuthorsMap | undefined,
|
|
61
|
+
): void {
|
|
62
|
+
if (!authorsMap) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const permalinkCounts = _(authorsMap)
|
|
67
|
+
// Filter to keep only authors with a page
|
|
68
|
+
.pickBy((author) => !!author.page)
|
|
69
|
+
// Group authors by their permalink
|
|
70
|
+
.groupBy((author) => author.page?.permalink)
|
|
71
|
+
// Filter to keep only permalinks with more than one author
|
|
72
|
+
.pickBy((authors) => authors.length > 1)
|
|
73
|
+
// Transform the object into an array of [permalink, authors] pairs
|
|
74
|
+
.toPairs()
|
|
75
|
+
.value();
|
|
76
|
+
|
|
77
|
+
if (permalinkCounts.length > 0) {
|
|
78
|
+
const errorMessage = permalinkCounts
|
|
79
|
+
.map(
|
|
80
|
+
([permalink, authors]) =>
|
|
81
|
+
`Permalink: ${permalink}\nAuthors: ${authors
|
|
82
|
+
.map((author) => author.name || 'Unknown')
|
|
83
|
+
.join(', ')}`,
|
|
84
|
+
)
|
|
85
|
+
.join('\n');
|
|
86
|
+
|
|
87
|
+
throw new Error(
|
|
88
|
+
`The following permalinks are duplicated:\n${errorMessage}`,
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function normalizeAuthor({
|
|
94
|
+
authorsBaseRoutePath,
|
|
95
|
+
authorKey,
|
|
96
|
+
author,
|
|
97
|
+
}: {
|
|
98
|
+
authorsBaseRoutePath: string;
|
|
99
|
+
authorKey: string;
|
|
100
|
+
author: AuthorInput;
|
|
101
|
+
}): Author & {key: string} {
|
|
102
|
+
function getAuthorPage(): AuthorPage | null {
|
|
103
|
+
if (!author.page) {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
const slug =
|
|
107
|
+
author.page === true ? _.kebabCase(authorKey) : author.page.permalink;
|
|
108
|
+
return {
|
|
109
|
+
permalink: normalizeUrl([authorsBaseRoutePath, slug]),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return {
|
|
114
|
+
...author,
|
|
115
|
+
key: authorKey,
|
|
116
|
+
page: getAuthorPage(),
|
|
117
|
+
socials: author.socials ? normalizeSocials(author.socials) : undefined,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function normalizeAuthorsMap({
|
|
122
|
+
authorsBaseRoutePath,
|
|
123
|
+
authorsMapInput,
|
|
124
|
+
}: {
|
|
125
|
+
authorsBaseRoutePath: string;
|
|
126
|
+
authorsMapInput: AuthorsMapInput;
|
|
127
|
+
}): AuthorsMap {
|
|
128
|
+
return _.mapValues(authorsMapInput, (author, authorKey) => {
|
|
129
|
+
return normalizeAuthor({authorsBaseRoutePath, authorKey, author});
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export function validateAuthorsMapInput(content: unknown): AuthorsMapInput {
|
|
134
|
+
const {error, value} = AuthorsMapInputSchema.validate(content);
|
|
135
|
+
if (error) {
|
|
136
|
+
throw error;
|
|
137
|
+
}
|
|
138
|
+
return value;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
async function getAuthorsMapInput(params: {
|
|
142
|
+
authorsMapPath: string;
|
|
143
|
+
contentPaths: BlogContentPaths;
|
|
144
|
+
}): Promise<AuthorsMapInput | undefined> {
|
|
145
|
+
const content = await readDataFile({
|
|
146
|
+
filePath: params.authorsMapPath,
|
|
147
|
+
contentPaths: params.contentPaths,
|
|
148
|
+
});
|
|
149
|
+
return content ? validateAuthorsMapInput(content) : undefined;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export async function getAuthorsMap(params: {
|
|
153
|
+
authorsMapPath: string;
|
|
154
|
+
authorsBaseRoutePath: string;
|
|
155
|
+
contentPaths: BlogContentPaths;
|
|
156
|
+
}): Promise<AuthorsMap | undefined> {
|
|
157
|
+
const authorsMapInput = await getAuthorsMapInput(params);
|
|
158
|
+
if (!authorsMapInput) {
|
|
159
|
+
return undefined;
|
|
160
|
+
}
|
|
161
|
+
const authorsMap = normalizeAuthorsMap({authorsMapInput, ...params});
|
|
162
|
+
return authorsMap;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export function validateAuthorsMap(content: unknown): AuthorsMapInput {
|
|
166
|
+
const {error, value} = AuthorsMapInputSchema.validate(content);
|
|
167
|
+
if (error) {
|
|
168
|
+
throw error;
|
|
169
|
+
}
|
|
170
|
+
return value;
|
|
171
|
+
}
|
package/src/blogUtils.ts
CHANGED
|
@@ -29,11 +29,12 @@ import {
|
|
|
29
29
|
} from '@docusaurus/utils';
|
|
30
30
|
import {getTagsFile} from '@docusaurus/utils-validation';
|
|
31
31
|
import {validateBlogPostFrontMatter} from './frontMatter';
|
|
32
|
-
import {
|
|
32
|
+
import {getBlogPostAuthors} from './authors';
|
|
33
33
|
import {reportAuthorsProblems} from './authorsProblems';
|
|
34
34
|
import type {TagsFile} from '@docusaurus/utils';
|
|
35
35
|
import type {LoadContext, ParseFrontMatter} from '@docusaurus/types';
|
|
36
36
|
import type {
|
|
37
|
+
AuthorsMap,
|
|
37
38
|
PluginOptions,
|
|
38
39
|
ReadingTimeFunction,
|
|
39
40
|
BlogPost,
|
|
@@ -64,7 +65,7 @@ export function paginateBlogPosts({
|
|
|
64
65
|
const totalCount = blogPosts.length;
|
|
65
66
|
const postsPerPage =
|
|
66
67
|
postsPerPageOption === 'ALL' ? totalCount : postsPerPageOption;
|
|
67
|
-
const numberOfPages = Math.ceil(totalCount / postsPerPage);
|
|
68
|
+
const numberOfPages = Math.max(1, Math.ceil(totalCount / postsPerPage));
|
|
68
69
|
|
|
69
70
|
const pages: BlogPaginated[] = [];
|
|
70
71
|
|
|
@@ -366,6 +367,7 @@ export async function generateBlogPosts(
|
|
|
366
367
|
contentPaths: BlogContentPaths,
|
|
367
368
|
context: LoadContext,
|
|
368
369
|
options: PluginOptions,
|
|
370
|
+
authorsMap?: AuthorsMap,
|
|
369
371
|
): Promise<BlogPost[]> {
|
|
370
372
|
const {include, exclude} = options;
|
|
371
373
|
|
|
@@ -378,11 +380,6 @@ export async function generateBlogPosts(
|
|
|
378
380
|
ignore: exclude,
|
|
379
381
|
});
|
|
380
382
|
|
|
381
|
-
const authorsMap = await getAuthorsMap({
|
|
382
|
-
contentPaths,
|
|
383
|
-
authorsMapPath: options.authorsMapPath,
|
|
384
|
-
});
|
|
385
|
-
|
|
386
383
|
const tagsFile = await getTagsFile({contentPaths, tags: options.tags});
|
|
387
384
|
|
|
388
385
|
async function doProcessBlogSourceFile(blogSourceFile: string) {
|
package/src/index.ts
CHANGED
|
@@ -34,6 +34,7 @@ import {translateContent, getTranslationFiles} from './translations';
|
|
|
34
34
|
import {createBlogFeedFiles, createFeedHtmlHeadTags} from './feed';
|
|
35
35
|
|
|
36
36
|
import {createAllRoutes} from './routes';
|
|
37
|
+
import {checkAuthorsMapPermalinkCollisions, getAuthorsMap} from './authorsMap';
|
|
37
38
|
import type {BlogContentPaths, BlogMarkdownLoaderOptions} from './types';
|
|
38
39
|
import type {LoadContext, Plugin} from '@docusaurus/types';
|
|
39
40
|
import type {
|
|
@@ -160,11 +161,30 @@ export default async function pluginContentBlog(
|
|
|
160
161
|
blogTitle,
|
|
161
162
|
blogSidebarTitle,
|
|
162
163
|
pageBasePath,
|
|
164
|
+
authorsBasePath,
|
|
165
|
+
authorsMapPath,
|
|
163
166
|
} = options;
|
|
164
167
|
|
|
165
168
|
const baseBlogUrl = normalizeUrl([baseUrl, routeBasePath]);
|
|
166
169
|
const blogTagsListPath = normalizeUrl([baseBlogUrl, tagsBasePath]);
|
|
167
|
-
|
|
170
|
+
|
|
171
|
+
const authorsMap = await getAuthorsMap({
|
|
172
|
+
contentPaths,
|
|
173
|
+
authorsMapPath,
|
|
174
|
+
authorsBaseRoutePath: normalizeUrl([
|
|
175
|
+
baseUrl,
|
|
176
|
+
routeBasePath,
|
|
177
|
+
authorsBasePath,
|
|
178
|
+
]),
|
|
179
|
+
});
|
|
180
|
+
checkAuthorsMapPermalinkCollisions(authorsMap);
|
|
181
|
+
|
|
182
|
+
let blogPosts = await generateBlogPosts(
|
|
183
|
+
contentPaths,
|
|
184
|
+
context,
|
|
185
|
+
options,
|
|
186
|
+
authorsMap,
|
|
187
|
+
);
|
|
168
188
|
blogPosts = await applyProcessBlogPosts({
|
|
169
189
|
blogPosts,
|
|
170
190
|
processBlogPosts: options.processBlogPosts,
|
|
@@ -178,6 +198,7 @@ export default async function pluginContentBlog(
|
|
|
178
198
|
blogListPaginated: [],
|
|
179
199
|
blogTags: {},
|
|
180
200
|
blogTagsListPath,
|
|
201
|
+
authorsMap,
|
|
181
202
|
};
|
|
182
203
|
}
|
|
183
204
|
|
|
@@ -226,6 +247,7 @@ export default async function pluginContentBlog(
|
|
|
226
247
|
blogListPaginated,
|
|
227
248
|
blogTags,
|
|
228
249
|
blogTagsListPath,
|
|
250
|
+
authorsMap,
|
|
229
251
|
};
|
|
230
252
|
},
|
|
231
253
|
|
package/src/options.ts
CHANGED
|
@@ -34,6 +34,8 @@ export const DEFAULT_OPTIONS: PluginOptions = {
|
|
|
34
34
|
showReadingTime: true,
|
|
35
35
|
blogTagsPostsComponent: '@theme/BlogTagsPostsPage',
|
|
36
36
|
blogTagsListComponent: '@theme/BlogTagsListPage',
|
|
37
|
+
blogAuthorsPostsComponent: '@theme/Blog/Pages/BlogAuthorsPostsPage',
|
|
38
|
+
blogAuthorsListComponent: '@theme/Blog/Pages/BlogAuthorsListPage',
|
|
37
39
|
blogPostComponent: '@theme/BlogPostPage',
|
|
38
40
|
blogListComponent: '@theme/BlogListPage',
|
|
39
41
|
blogArchiveComponent: '@theme/BlogArchivePage',
|
|
@@ -58,6 +60,7 @@ export const DEFAULT_OPTIONS: PluginOptions = {
|
|
|
58
60
|
processBlogPosts: async () => undefined,
|
|
59
61
|
onInlineTags: 'warn',
|
|
60
62
|
tags: undefined,
|
|
63
|
+
authorsBasePath: 'authors',
|
|
61
64
|
onInlineAuthors: 'warn',
|
|
62
65
|
};
|
|
63
66
|
|
|
@@ -82,6 +85,12 @@ const PluginOptionSchema = Joi.object<PluginOptions>({
|
|
|
82
85
|
blogTagsPostsComponent: Joi.string().default(
|
|
83
86
|
DEFAULT_OPTIONS.blogTagsPostsComponent,
|
|
84
87
|
),
|
|
88
|
+
blogAuthorsPostsComponent: Joi.string().default(
|
|
89
|
+
DEFAULT_OPTIONS.blogAuthorsPostsComponent,
|
|
90
|
+
),
|
|
91
|
+
blogAuthorsListComponent: Joi.string().default(
|
|
92
|
+
DEFAULT_OPTIONS.blogAuthorsListComponent,
|
|
93
|
+
),
|
|
85
94
|
blogArchiveComponent: Joi.string().default(
|
|
86
95
|
DEFAULT_OPTIONS.blogArchiveComponent,
|
|
87
96
|
),
|
|
@@ -157,6 +166,9 @@ const PluginOptionSchema = Joi.object<PluginOptions>({
|
|
|
157
166
|
.disallow('')
|
|
158
167
|
.allow(null, false)
|
|
159
168
|
.default(() => DEFAULT_OPTIONS.tags),
|
|
169
|
+
authorsBasePath: Joi.string()
|
|
170
|
+
.default(DEFAULT_OPTIONS.authorsBasePath)
|
|
171
|
+
.disallow(''),
|
|
160
172
|
onInlineAuthors: Joi.string()
|
|
161
173
|
.equal('ignore', 'log', 'warn', 'throw')
|
|
162
174
|
.default(DEFAULT_OPTIONS.onInlineAuthors),
|