@docusaurus/plugin-content-blog 0.0.0-6012 → 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/lib/authors.d.ts
CHANGED
|
@@ -4,20 +4,19 @@
|
|
|
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 type { Author, BlogPostFrontMatter } from '@docusaurus/plugin-content-blog';
|
|
9
|
-
export type AuthorsMap = {
|
|
10
|
-
[authorKey: string]: Author;
|
|
11
|
-
};
|
|
12
|
-
export declare function validateAuthorsMap(content: unknown): AuthorsMap;
|
|
13
|
-
export declare function getAuthorsMap(params: {
|
|
14
|
-
authorsMapPath: string;
|
|
15
|
-
contentPaths: BlogContentPaths;
|
|
16
|
-
}): Promise<AuthorsMap | undefined>;
|
|
7
|
+
import type { Author, AuthorsMap, BlogPost, BlogPostFrontMatter } from '@docusaurus/plugin-content-blog';
|
|
17
8
|
type AuthorsParam = {
|
|
18
9
|
frontMatter: BlogPostFrontMatter;
|
|
19
10
|
authorsMap: AuthorsMap | undefined;
|
|
20
11
|
baseUrl: string;
|
|
21
12
|
};
|
|
22
13
|
export declare function getBlogPostAuthors(params: AuthorsParam): Author[];
|
|
14
|
+
/**
|
|
15
|
+
* Group blog posts by author key
|
|
16
|
+
* Blog posts with only inline authors are ignored
|
|
17
|
+
*/
|
|
18
|
+
export declare function groupBlogPostsByAuthorKey({ blogPosts, authorsMap, }: {
|
|
19
|
+
blogPosts: BlogPost[];
|
|
20
|
+
authorsMap: AuthorsMap | undefined;
|
|
21
|
+
}): Record<string, BlogPost[]>;
|
|
23
22
|
export {};
|
package/lib/authors.js
CHANGED
|
@@ -6,60 +6,11 @@
|
|
|
6
6
|
* LICENSE file in the root directory of this source tree.
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.validateAuthorsMap = validateAuthorsMap;
|
|
10
|
-
exports.getAuthorsMap = getAuthorsMap;
|
|
11
9
|
exports.getBlogPostAuthors = getBlogPostAuthors;
|
|
10
|
+
exports.groupBlogPostsByAuthorKey = groupBlogPostsByAuthorKey;
|
|
12
11
|
const tslib_1 = require("tslib");
|
|
13
|
-
const
|
|
12
|
+
const lodash_1 = tslib_1.__importDefault(require("lodash"));
|
|
14
13
|
const utils_1 = require("@docusaurus/utils");
|
|
15
|
-
const utils_validation_1 = require("@docusaurus/utils-validation");
|
|
16
|
-
const authorsSocials_1 = require("./authorsSocials");
|
|
17
|
-
const AuthorsMapSchema = utils_validation_1.Joi.object()
|
|
18
|
-
.pattern(utils_validation_1.Joi.string(), utils_validation_1.Joi.object({
|
|
19
|
-
name: utils_validation_1.Joi.string(),
|
|
20
|
-
url: utils_validation_1.URISchema,
|
|
21
|
-
imageURL: utils_validation_1.URISchema,
|
|
22
|
-
title: utils_validation_1.Joi.string(),
|
|
23
|
-
email: utils_validation_1.Joi.string(),
|
|
24
|
-
socials: authorsSocials_1.AuthorSocialsSchema,
|
|
25
|
-
})
|
|
26
|
-
.rename('image_url', 'imageURL')
|
|
27
|
-
.or('name', 'imageURL')
|
|
28
|
-
.unknown()
|
|
29
|
-
.required()
|
|
30
|
-
.messages({
|
|
31
|
-
'object.base': '{#label} should be an author object containing properties like name, title, and imageURL.',
|
|
32
|
-
'any.required': '{#label} cannot be undefined. It should be an author object containing properties like name, title, and imageURL.',
|
|
33
|
-
}))
|
|
34
|
-
.messages({
|
|
35
|
-
'object.base': "The authors map file should contain an object where each entry contains an author key and the corresponding author's data.",
|
|
36
|
-
});
|
|
37
|
-
function validateAuthorsMap(content) {
|
|
38
|
-
const { error, value } = AuthorsMapSchema.validate(content);
|
|
39
|
-
if (error) {
|
|
40
|
-
throw error;
|
|
41
|
-
}
|
|
42
|
-
return value;
|
|
43
|
-
}
|
|
44
|
-
function normalizeAuthor(author) {
|
|
45
|
-
return {
|
|
46
|
-
...author,
|
|
47
|
-
socials: author.socials ? (0, authorsSocials_1.normalizeSocials)(author.socials) : undefined,
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
function normalizeAuthorsMap(authorsMap) {
|
|
51
|
-
return _.mapValues(authorsMap, normalizeAuthor);
|
|
52
|
-
}
|
|
53
|
-
async function getAuthorsMap(params) {
|
|
54
|
-
const authorsMap = await (0, utils_1.getDataFileData)({
|
|
55
|
-
filePath: params.authorsMapPath,
|
|
56
|
-
contentPaths: params.contentPaths,
|
|
57
|
-
fileType: 'authors map',
|
|
58
|
-
},
|
|
59
|
-
// TODO annoying to test: tightly coupled FS reads + validation...
|
|
60
|
-
validateAuthorsMap);
|
|
61
|
-
return authorsMap ? normalizeAuthorsMap(authorsMap) : undefined;
|
|
62
|
-
}
|
|
63
14
|
function normalizeImageUrl({ imageURL, baseUrl, }) {
|
|
64
15
|
return imageURL?.startsWith('/')
|
|
65
16
|
? (0, utils_1.normalizeUrl)([baseUrl, imageURL])
|
|
@@ -67,6 +18,7 @@ function normalizeImageUrl({ imageURL, baseUrl, }) {
|
|
|
67
18
|
}
|
|
68
19
|
// Legacy v1/early-v2 front matter fields
|
|
69
20
|
// We may want to deprecate those in favor of using only frontMatter.authors
|
|
21
|
+
// TODO Docusaurus v4: remove this legacy front matter
|
|
70
22
|
function getFrontMatterAuthorLegacy({ baseUrl, frontMatter, }) {
|
|
71
23
|
const name = frontMatter.author;
|
|
72
24
|
const title = frontMatter.author_title ?? frontMatter.authorTitle;
|
|
@@ -81,27 +33,33 @@ function getFrontMatterAuthorLegacy({ baseUrl, frontMatter, }) {
|
|
|
81
33
|
title,
|
|
82
34
|
url,
|
|
83
35
|
imageURL,
|
|
36
|
+
// legacy front matter authors do not have an author key/page
|
|
37
|
+
key: null,
|
|
38
|
+
page: null,
|
|
84
39
|
};
|
|
85
40
|
}
|
|
86
41
|
return undefined;
|
|
87
42
|
}
|
|
88
|
-
function
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
43
|
+
function getFrontMatterAuthors(params) {
|
|
44
|
+
const { authorsMap, frontMatter, baseUrl } = params;
|
|
45
|
+
return normalizeFrontMatterAuthors().map(toAuthor);
|
|
46
|
+
function normalizeFrontMatterAuthors() {
|
|
47
|
+
if (frontMatter.authors === undefined) {
|
|
48
|
+
return [];
|
|
49
|
+
}
|
|
50
|
+
function normalizeAuthor(authorInput) {
|
|
51
|
+
if (typeof authorInput === 'string') {
|
|
52
|
+
// We could allow users to provide an author's name here, but we only
|
|
53
|
+
// support keys, otherwise, a typo in a key would fall back to
|
|
54
|
+
// becoming a name and may end up unnoticed
|
|
55
|
+
return { key: authorInput };
|
|
56
|
+
}
|
|
57
|
+
return authorInput;
|
|
95
58
|
}
|
|
96
|
-
return
|
|
59
|
+
return Array.isArray(frontMatter.authors)
|
|
60
|
+
? frontMatter.authors.map(normalizeAuthor)
|
|
61
|
+
: [normalizeAuthor(frontMatter.authors)];
|
|
97
62
|
}
|
|
98
|
-
return Array.isArray(frontMatterAuthors)
|
|
99
|
-
? frontMatterAuthors.map(normalizeFrontMatterAuthor)
|
|
100
|
-
: [normalizeFrontMatterAuthor(frontMatterAuthors)];
|
|
101
|
-
}
|
|
102
|
-
function getFrontMatterAuthors(params) {
|
|
103
|
-
const { authorsMap } = params;
|
|
104
|
-
const frontMatterAuthors = normalizeFrontMatterAuthors(params.frontMatter.authors);
|
|
105
63
|
function getAuthorsMapAuthor(key) {
|
|
106
64
|
if (key) {
|
|
107
65
|
if (!authorsMap || Object.keys(authorsMap).length === 0) {
|
|
@@ -121,32 +79,37 @@ ${Object.keys(authorsMap)
|
|
|
121
79
|
return undefined;
|
|
122
80
|
}
|
|
123
81
|
function toAuthor(frontMatterAuthor) {
|
|
124
|
-
|
|
82
|
+
const author = {
|
|
125
83
|
// Author def from authorsMap can be locally overridden by front matter
|
|
126
84
|
...getAuthorsMapAuthor(frontMatterAuthor.key),
|
|
127
85
|
...frontMatterAuthor,
|
|
128
|
-
}
|
|
86
|
+
};
|
|
87
|
+
return {
|
|
88
|
+
...author,
|
|
89
|
+
key: author.key ?? null,
|
|
90
|
+
page: author.page ?? null,
|
|
91
|
+
imageURL: normalizeImageUrl({ imageURL: author.imageURL, baseUrl }),
|
|
92
|
+
};
|
|
129
93
|
}
|
|
130
|
-
return frontMatterAuthors.map(toAuthor);
|
|
131
|
-
}
|
|
132
|
-
function fixAuthorImageBaseURL(authors, { baseUrl }) {
|
|
133
|
-
return authors.map((author) => ({
|
|
134
|
-
...author,
|
|
135
|
-
imageURL: normalizeImageUrl({ imageURL: author.imageURL, baseUrl }),
|
|
136
|
-
}));
|
|
137
94
|
}
|
|
138
95
|
function getBlogPostAuthors(params) {
|
|
139
96
|
const authorLegacy = getFrontMatterAuthorLegacy(params);
|
|
140
97
|
const authors = getFrontMatterAuthors(params);
|
|
141
|
-
const updatedAuthors = fixAuthorImageBaseURL(authors, params);
|
|
142
98
|
if (authorLegacy) {
|
|
143
99
|
// Technically, we could allow mixing legacy/authors front matter, but do we
|
|
144
100
|
// really want to?
|
|
145
|
-
if (
|
|
101
|
+
if (authors.length > 0) {
|
|
146
102
|
throw new Error(`To declare blog post authors, use the 'authors' front matter in priority.
|
|
147
103
|
Don't mix 'authors' with other existing 'author_*' front matter. Choose one or the other, not both at the same time.`);
|
|
148
104
|
}
|
|
149
105
|
return [authorLegacy];
|
|
150
106
|
}
|
|
151
|
-
return
|
|
107
|
+
return authors;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Group blog posts by author key
|
|
111
|
+
* Blog posts with only inline authors are ignored
|
|
112
|
+
*/
|
|
113
|
+
function groupBlogPostsByAuthorKey({ blogPosts, authorsMap, }) {
|
|
114
|
+
return lodash_1.default.mapValues(authorsMap, (author, key) => blogPosts.filter((p) => p.metadata.authors.some((a) => a.key === key)));
|
|
152
115
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
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 { BlogContentPaths } from './types';
|
|
8
|
+
import type { AuthorAttributes, AuthorPage, AuthorsMap } from '@docusaurus/plugin-content-blog';
|
|
9
|
+
type AuthorInput = AuthorAttributes & {
|
|
10
|
+
page?: boolean | AuthorPage;
|
|
11
|
+
};
|
|
12
|
+
export type AuthorsMapInput = {
|
|
13
|
+
[authorKey: string]: AuthorInput;
|
|
14
|
+
};
|
|
15
|
+
export declare function checkAuthorsMapPermalinkCollisions(authorsMap: AuthorsMap | undefined): void;
|
|
16
|
+
export declare function validateAuthorsMapInput(content: unknown): AuthorsMapInput;
|
|
17
|
+
export declare function getAuthorsMap(params: {
|
|
18
|
+
authorsMapPath: string;
|
|
19
|
+
authorsBaseRoutePath: string;
|
|
20
|
+
contentPaths: BlogContentPaths;
|
|
21
|
+
}): Promise<AuthorsMap | undefined>;
|
|
22
|
+
export declare function validateAuthorsMap(content: unknown): AuthorsMapInput;
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,116 @@
|
|
|
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.checkAuthorsMapPermalinkCollisions = checkAuthorsMapPermalinkCollisions;
|
|
10
|
+
exports.validateAuthorsMapInput = validateAuthorsMapInput;
|
|
11
|
+
exports.getAuthorsMap = getAuthorsMap;
|
|
12
|
+
exports.validateAuthorsMap = validateAuthorsMap;
|
|
13
|
+
const tslib_1 = require("tslib");
|
|
14
|
+
const lodash_1 = tslib_1.__importDefault(require("lodash"));
|
|
15
|
+
const utils_1 = require("@docusaurus/utils");
|
|
16
|
+
const utils_validation_1 = require("@docusaurus/utils-validation");
|
|
17
|
+
const authorsSocials_1 = require("./authorsSocials");
|
|
18
|
+
const AuthorPageSchema = utils_validation_1.Joi.object({
|
|
19
|
+
permalink: utils_validation_1.Joi.string().required(),
|
|
20
|
+
});
|
|
21
|
+
const AuthorsMapInputSchema = utils_validation_1.Joi.object()
|
|
22
|
+
.pattern(utils_validation_1.Joi.string(), utils_validation_1.Joi.object({
|
|
23
|
+
name: utils_validation_1.Joi.string(),
|
|
24
|
+
url: utils_validation_1.URISchema,
|
|
25
|
+
imageURL: utils_validation_1.URISchema,
|
|
26
|
+
title: utils_validation_1.Joi.string(),
|
|
27
|
+
email: utils_validation_1.Joi.string(),
|
|
28
|
+
page: utils_validation_1.Joi.alternatives(utils_validation_1.Joi.bool(), AuthorPageSchema),
|
|
29
|
+
socials: authorsSocials_1.AuthorSocialsSchema,
|
|
30
|
+
description: utils_validation_1.Joi.string(),
|
|
31
|
+
})
|
|
32
|
+
.rename('image_url', 'imageURL')
|
|
33
|
+
.or('name', 'imageURL')
|
|
34
|
+
.unknown()
|
|
35
|
+
.required()
|
|
36
|
+
.messages({
|
|
37
|
+
'object.base': '{#label} should be an author object containing properties like name, title, and imageURL.',
|
|
38
|
+
'any.required': '{#label} cannot be undefined. It should be an author object containing properties like name, title, and imageURL.',
|
|
39
|
+
}))
|
|
40
|
+
.messages({
|
|
41
|
+
'object.base': "The authors map file should contain an object where each entry contains an author key and the corresponding author's data.",
|
|
42
|
+
});
|
|
43
|
+
function checkAuthorsMapPermalinkCollisions(authorsMap) {
|
|
44
|
+
if (!authorsMap) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const permalinkCounts = (0, lodash_1.default)(authorsMap)
|
|
48
|
+
// Filter to keep only authors with a page
|
|
49
|
+
.pickBy((author) => !!author.page)
|
|
50
|
+
// Group authors by their permalink
|
|
51
|
+
.groupBy((author) => author.page?.permalink)
|
|
52
|
+
// Filter to keep only permalinks with more than one author
|
|
53
|
+
.pickBy((authors) => authors.length > 1)
|
|
54
|
+
// Transform the object into an array of [permalink, authors] pairs
|
|
55
|
+
.toPairs()
|
|
56
|
+
.value();
|
|
57
|
+
if (permalinkCounts.length > 0) {
|
|
58
|
+
const errorMessage = permalinkCounts
|
|
59
|
+
.map(([permalink, authors]) => `Permalink: ${permalink}\nAuthors: ${authors
|
|
60
|
+
.map((author) => author.name || 'Unknown')
|
|
61
|
+
.join(', ')}`)
|
|
62
|
+
.join('\n');
|
|
63
|
+
throw new Error(`The following permalinks are duplicated:\n${errorMessage}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function normalizeAuthor({ authorsBaseRoutePath, authorKey, author, }) {
|
|
67
|
+
function getAuthorPage() {
|
|
68
|
+
if (!author.page) {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
const slug = author.page === true ? lodash_1.default.kebabCase(authorKey) : author.page.permalink;
|
|
72
|
+
return {
|
|
73
|
+
permalink: (0, utils_1.normalizeUrl)([authorsBaseRoutePath, slug]),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
...author,
|
|
78
|
+
key: authorKey,
|
|
79
|
+
page: getAuthorPage(),
|
|
80
|
+
socials: author.socials ? (0, authorsSocials_1.normalizeSocials)(author.socials) : undefined,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function normalizeAuthorsMap({ authorsBaseRoutePath, authorsMapInput, }) {
|
|
84
|
+
return lodash_1.default.mapValues(authorsMapInput, (author, authorKey) => {
|
|
85
|
+
return normalizeAuthor({ authorsBaseRoutePath, authorKey, author });
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
function validateAuthorsMapInput(content) {
|
|
89
|
+
const { error, value } = AuthorsMapInputSchema.validate(content);
|
|
90
|
+
if (error) {
|
|
91
|
+
throw error;
|
|
92
|
+
}
|
|
93
|
+
return value;
|
|
94
|
+
}
|
|
95
|
+
async function getAuthorsMapInput(params) {
|
|
96
|
+
const content = await (0, utils_1.readDataFile)({
|
|
97
|
+
filePath: params.authorsMapPath,
|
|
98
|
+
contentPaths: params.contentPaths,
|
|
99
|
+
});
|
|
100
|
+
return content ? validateAuthorsMapInput(content) : undefined;
|
|
101
|
+
}
|
|
102
|
+
async function getAuthorsMap(params) {
|
|
103
|
+
const authorsMapInput = await getAuthorsMapInput(params);
|
|
104
|
+
if (!authorsMapInput) {
|
|
105
|
+
return undefined;
|
|
106
|
+
}
|
|
107
|
+
const authorsMap = normalizeAuthorsMap({ authorsMapInput, ...params });
|
|
108
|
+
return authorsMap;
|
|
109
|
+
}
|
|
110
|
+
function validateAuthorsMap(content) {
|
|
111
|
+
const { error, value } = AuthorsMapInputSchema.validate(content);
|
|
112
|
+
if (error) {
|
|
113
|
+
throw error;
|
|
114
|
+
}
|
|
115
|
+
return value;
|
|
116
|
+
}
|
package/lib/blogUtils.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
import type { LoadContext } from '@docusaurus/types';
|
|
8
|
-
import type { PluginOptions, BlogPost, BlogTags, BlogPaginated } from '@docusaurus/plugin-content-blog';
|
|
8
|
+
import type { AuthorsMap, PluginOptions, BlogPost, BlogTags, BlogPaginated } from '@docusaurus/plugin-content-blog';
|
|
9
9
|
import type { BlogContentPaths } from './types';
|
|
10
10
|
export declare function truncate(fileString: string, truncateMarker: RegExp): string;
|
|
11
11
|
export declare function paginateBlogPosts({ blogPosts, basePageUrl, blogTitle, blogDescription, postsPerPageOption, pageBasePath, }: {
|
|
@@ -30,7 +30,7 @@ type ParsedBlogFileName = {
|
|
|
30
30
|
slug: string;
|
|
31
31
|
};
|
|
32
32
|
export declare function parseBlogFileName(blogSourceRelative: string): ParsedBlogFileName;
|
|
33
|
-
export declare function generateBlogPosts(contentPaths: BlogContentPaths, context: LoadContext, options: PluginOptions): Promise<BlogPost[]>;
|
|
33
|
+
export declare function generateBlogPosts(contentPaths: BlogContentPaths, context: LoadContext, options: PluginOptions, authorsMap?: AuthorsMap): Promise<BlogPost[]>;
|
|
34
34
|
export declare function applyProcessBlogPosts({ blogPosts, processBlogPosts, }: {
|
|
35
35
|
blogPosts: BlogPost[];
|
|
36
36
|
processBlogPosts: PluginOptions['processBlogPosts'];
|
package/lib/blogUtils.js
CHANGED
|
@@ -30,7 +30,7 @@ function truncate(fileString, truncateMarker) {
|
|
|
30
30
|
function paginateBlogPosts({ blogPosts, basePageUrl, blogTitle, blogDescription, postsPerPageOption, pageBasePath, }) {
|
|
31
31
|
const totalCount = blogPosts.length;
|
|
32
32
|
const postsPerPage = postsPerPageOption === 'ALL' ? totalCount : postsPerPageOption;
|
|
33
|
-
const numberOfPages = Math.ceil(totalCount / postsPerPage);
|
|
33
|
+
const numberOfPages = Math.max(1, Math.ceil(totalCount / postsPerPage));
|
|
34
34
|
const pages = [];
|
|
35
35
|
function permalink(page) {
|
|
36
36
|
return page > 0
|
|
@@ -236,7 +236,7 @@ async function processBlogSourceFile(blogSourceRelative, contentPaths, context,
|
|
|
236
236
|
content,
|
|
237
237
|
};
|
|
238
238
|
}
|
|
239
|
-
async function generateBlogPosts(contentPaths, context, options) {
|
|
239
|
+
async function generateBlogPosts(contentPaths, context, options, authorsMap) {
|
|
240
240
|
const { include, exclude } = options;
|
|
241
241
|
if (!(await fs_extra_1.default.pathExists(contentPaths.contentPath))) {
|
|
242
242
|
return [];
|
|
@@ -245,10 +245,6 @@ async function generateBlogPosts(contentPaths, context, options) {
|
|
|
245
245
|
cwd: contentPaths.contentPath,
|
|
246
246
|
ignore: exclude,
|
|
247
247
|
});
|
|
248
|
-
const authorsMap = await (0, authors_1.getAuthorsMap)({
|
|
249
|
-
contentPaths,
|
|
250
|
-
authorsMapPath: options.authorsMapPath,
|
|
251
|
-
});
|
|
252
248
|
const tagsFile = await (0, utils_validation_1.getTagsFile)({ contentPaths, tags: options.tags });
|
|
253
249
|
async function doProcessBlogSourceFile(blogSourceFile) {
|
|
254
250
|
try {
|
package/lib/index.js
CHANGED
|
@@ -18,6 +18,7 @@ const footnoteIDFixer_1 = tslib_1.__importDefault(require("./remark/footnoteIDFi
|
|
|
18
18
|
const translations_1 = require("./translations");
|
|
19
19
|
const feed_1 = require("./feed");
|
|
20
20
|
const routes_1 = require("./routes");
|
|
21
|
+
const authorsMap_1 = require("./authorsMap");
|
|
21
22
|
const PluginName = 'docusaurus-plugin-content-blog';
|
|
22
23
|
// TODO this is bad, we should have a better way to do this (new lifecycle?)
|
|
23
24
|
// The source to permalink is currently a mutable map passed to the mdx loader
|
|
@@ -88,10 +89,20 @@ async function pluginContentBlog(context, options) {
|
|
|
88
89
|
},
|
|
89
90
|
// Fetches blog contents and returns metadata for the necessary routes.
|
|
90
91
|
async loadContent() {
|
|
91
|
-
const { postsPerPage: postsPerPageOption, routeBasePath, tagsBasePath, blogDescription, blogTitle, blogSidebarTitle, pageBasePath, } = options;
|
|
92
|
+
const { postsPerPage: postsPerPageOption, routeBasePath, tagsBasePath, blogDescription, blogTitle, blogSidebarTitle, pageBasePath, authorsBasePath, authorsMapPath, } = options;
|
|
92
93
|
const baseBlogUrl = (0, utils_1.normalizeUrl)([baseUrl, routeBasePath]);
|
|
93
94
|
const blogTagsListPath = (0, utils_1.normalizeUrl)([baseBlogUrl, tagsBasePath]);
|
|
94
|
-
|
|
95
|
+
const authorsMap = await (0, authorsMap_1.getAuthorsMap)({
|
|
96
|
+
contentPaths,
|
|
97
|
+
authorsMapPath,
|
|
98
|
+
authorsBaseRoutePath: (0, utils_1.normalizeUrl)([
|
|
99
|
+
baseUrl,
|
|
100
|
+
routeBasePath,
|
|
101
|
+
authorsBasePath,
|
|
102
|
+
]),
|
|
103
|
+
});
|
|
104
|
+
(0, authorsMap_1.checkAuthorsMapPermalinkCollisions)(authorsMap);
|
|
105
|
+
let blogPosts = await (0, blogUtils_1.generateBlogPosts)(contentPaths, context, options, authorsMap);
|
|
95
106
|
blogPosts = await (0, blogUtils_1.applyProcessBlogPosts)({
|
|
96
107
|
blogPosts,
|
|
97
108
|
processBlogPosts: options.processBlogPosts,
|
|
@@ -104,6 +115,7 @@ async function pluginContentBlog(context, options) {
|
|
|
104
115
|
blogListPaginated: [],
|
|
105
116
|
blogTags: {},
|
|
106
117
|
blogTagsListPath,
|
|
118
|
+
authorsMap,
|
|
107
119
|
};
|
|
108
120
|
}
|
|
109
121
|
// Collocate next and prev metadata.
|
|
@@ -146,6 +158,7 @@ async function pluginContentBlog(context, options) {
|
|
|
146
158
|
blogListPaginated,
|
|
147
159
|
blogTags,
|
|
148
160
|
blogTagsListPath,
|
|
161
|
+
authorsMap,
|
|
149
162
|
};
|
|
150
163
|
},
|
|
151
164
|
async contentLoaded({ content, actions }) {
|
package/lib/options.js
CHANGED
|
@@ -22,6 +22,8 @@ exports.DEFAULT_OPTIONS = {
|
|
|
22
22
|
showReadingTime: true,
|
|
23
23
|
blogTagsPostsComponent: '@theme/BlogTagsPostsPage',
|
|
24
24
|
blogTagsListComponent: '@theme/BlogTagsListPage',
|
|
25
|
+
blogAuthorsPostsComponent: '@theme/Blog/Pages/BlogAuthorsPostsPage',
|
|
26
|
+
blogAuthorsListComponent: '@theme/Blog/Pages/BlogAuthorsListPage',
|
|
25
27
|
blogPostComponent: '@theme/BlogPostPage',
|
|
26
28
|
blogListComponent: '@theme/BlogListPage',
|
|
27
29
|
blogArchiveComponent: '@theme/BlogArchivePage',
|
|
@@ -46,6 +48,7 @@ exports.DEFAULT_OPTIONS = {
|
|
|
46
48
|
processBlogPosts: async () => undefined,
|
|
47
49
|
onInlineTags: 'warn',
|
|
48
50
|
tags: undefined,
|
|
51
|
+
authorsBasePath: 'authors',
|
|
49
52
|
onInlineAuthors: 'warn',
|
|
50
53
|
};
|
|
51
54
|
const PluginOptionSchema = utils_validation_1.Joi.object({
|
|
@@ -65,6 +68,8 @@ const PluginOptionSchema = utils_validation_1.Joi.object({
|
|
|
65
68
|
blogPostComponent: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.blogPostComponent),
|
|
66
69
|
blogTagsListComponent: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.blogTagsListComponent),
|
|
67
70
|
blogTagsPostsComponent: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.blogTagsPostsComponent),
|
|
71
|
+
blogAuthorsPostsComponent: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.blogAuthorsPostsComponent),
|
|
72
|
+
blogAuthorsListComponent: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.blogAuthorsListComponent),
|
|
68
73
|
blogArchiveComponent: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.blogArchiveComponent),
|
|
69
74
|
blogTitle: utils_validation_1.Joi.string().allow('').default(exports.DEFAULT_OPTIONS.blogTitle),
|
|
70
75
|
blogDescription: utils_validation_1.Joi.string()
|
|
@@ -124,6 +129,9 @@ const PluginOptionSchema = utils_validation_1.Joi.object({
|
|
|
124
129
|
.disallow('')
|
|
125
130
|
.allow(null, false)
|
|
126
131
|
.default(() => exports.DEFAULT_OPTIONS.tags),
|
|
132
|
+
authorsBasePath: utils_validation_1.Joi.string()
|
|
133
|
+
.default(exports.DEFAULT_OPTIONS.authorsBasePath)
|
|
134
|
+
.disallow(''),
|
|
127
135
|
onInlineAuthors: utils_validation_1.Joi.string()
|
|
128
136
|
.equal('ignore', 'log', 'warn', 'throw')
|
|
129
137
|
.default(exports.DEFAULT_OPTIONS.onInlineAuthors),
|
package/lib/props.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
import type { TagsListItem, TagModule } from '@docusaurus/utils';
|
|
8
|
-
import type { BlogPost, BlogSidebar, BlogTag, BlogTags } from '@docusaurus/plugin-content-blog';
|
|
8
|
+
import type { AuthorItemProp, AuthorWithKey, BlogPost, BlogSidebar, BlogTag, BlogTags } from '@docusaurus/plugin-content-blog';
|
|
9
9
|
export declare function toTagsProp({ blogTags }: {
|
|
10
10
|
blogTags: BlogTags;
|
|
11
11
|
}): TagsListItem[];
|
|
@@ -13,6 +13,10 @@ export declare function toTagProp({ blogTagsListPath, tag, }: {
|
|
|
13
13
|
blogTagsListPath: string;
|
|
14
14
|
tag: BlogTag;
|
|
15
15
|
}): TagModule;
|
|
16
|
+
export declare function toAuthorItemProp({ author, count, }: {
|
|
17
|
+
author: AuthorWithKey;
|
|
18
|
+
count: number;
|
|
19
|
+
}): AuthorItemProp;
|
|
16
20
|
export declare function toBlogSidebarProp({ blogSidebarTitle, blogPosts, }: {
|
|
17
21
|
blogSidebarTitle: string;
|
|
18
22
|
blogPosts: BlogPost[];
|
package/lib/props.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.toTagsProp = toTagsProp;
|
|
4
4
|
exports.toTagProp = toTagProp;
|
|
5
|
+
exports.toAuthorItemProp = toAuthorItemProp;
|
|
5
6
|
exports.toBlogSidebarProp = toBlogSidebarProp;
|
|
6
7
|
function toTagsProp({ blogTags }) {
|
|
7
8
|
return Object.values(blogTags)
|
|
@@ -23,6 +24,12 @@ function toTagProp({ blogTagsListPath, tag, }) {
|
|
|
23
24
|
unlisted: tag.unlisted,
|
|
24
25
|
};
|
|
25
26
|
}
|
|
27
|
+
function toAuthorItemProp({ author, count, }) {
|
|
28
|
+
return {
|
|
29
|
+
...author,
|
|
30
|
+
count,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
26
33
|
function toBlogSidebarProp({ blogSidebarTitle, blogPosts, }) {
|
|
27
34
|
return {
|
|
28
35
|
title: blogSidebarTitle,
|
package/lib/routes.js
CHANGED
|
@@ -13,15 +13,21 @@ const lodash_1 = tslib_1.__importDefault(require("lodash"));
|
|
|
13
13
|
const utils_1 = require("@docusaurus/utils");
|
|
14
14
|
const blogUtils_1 = require("./blogUtils");
|
|
15
15
|
const props_1 = require("./props");
|
|
16
|
+
const authors_1 = require("./authors");
|
|
16
17
|
async function createAllRoutes(param) {
|
|
17
18
|
const routes = await buildAllRoutes(param);
|
|
18
19
|
routes.forEach(param.actions.addRoute);
|
|
19
20
|
}
|
|
20
21
|
async function buildAllRoutes({ baseUrl, content, actions, options, aliasedSource, }) {
|
|
21
|
-
const { blogListComponent, blogPostComponent, blogTagsListComponent, blogTagsPostsComponent, blogArchiveComponent, routeBasePath, archiveBasePath, blogTitle, } = options;
|
|
22
|
+
const { blogListComponent, blogPostComponent, blogTagsListComponent, blogAuthorsListComponent, blogAuthorsPostsComponent, blogTagsPostsComponent, blogArchiveComponent, routeBasePath, archiveBasePath, blogTitle, authorsBasePath, postsPerPage, blogDescription, } = options;
|
|
22
23
|
const pluginId = options.id;
|
|
23
24
|
const { createData } = actions;
|
|
24
|
-
const { blogSidebarTitle, blogPosts, blogListPaginated, blogTags, blogTagsListPath, } = content;
|
|
25
|
+
const { blogSidebarTitle, blogPosts, blogListPaginated, blogTags, blogTagsListPath, authorsMap, } = content;
|
|
26
|
+
const authorsListPath = (0, utils_1.normalizeUrl)([
|
|
27
|
+
baseUrl,
|
|
28
|
+
routeBasePath,
|
|
29
|
+
authorsBasePath,
|
|
30
|
+
]);
|
|
25
31
|
const listedBlogPosts = blogPosts.filter(blogUtils_1.shouldBeListed);
|
|
26
32
|
const blogPostsById = lodash_1.default.keyBy(blogPosts, (post) => post.id);
|
|
27
33
|
function getBlogPostById(id) {
|
|
@@ -46,6 +52,7 @@ async function buildAllRoutes({ baseUrl, content, actions, options, aliasedSourc
|
|
|
46
52
|
const blogMetadata = {
|
|
47
53
|
blogBasePath: (0, utils_1.normalizeUrl)([baseUrl, routeBasePath]),
|
|
48
54
|
blogTitle,
|
|
55
|
+
authorsListPath,
|
|
49
56
|
};
|
|
50
57
|
const modulePath = await createData(`blogMetadata-${pluginId}.json`, blogMetadata);
|
|
51
58
|
return aliasedSource(modulePath);
|
|
@@ -168,10 +175,76 @@ async function buildAllRoutes({ baseUrl, content, actions, options, aliasedSourc
|
|
|
168
175
|
const tagsPaginatedRoutes = Object.values(blogTags).flatMap(createTagPaginatedRoutes);
|
|
169
176
|
return [tagsListRoute, ...tagsPaginatedRoutes];
|
|
170
177
|
}
|
|
178
|
+
function createAuthorsRoutes() {
|
|
179
|
+
if (authorsMap === undefined || Object.keys(authorsMap).length === 0) {
|
|
180
|
+
return [];
|
|
181
|
+
}
|
|
182
|
+
const blogPostsByAuthorKey = (0, authors_1.groupBlogPostsByAuthorKey)({
|
|
183
|
+
authorsMap,
|
|
184
|
+
blogPosts,
|
|
185
|
+
});
|
|
186
|
+
const authors = Object.values(authorsMap);
|
|
187
|
+
return [
|
|
188
|
+
createAuthorListRoute(),
|
|
189
|
+
...authors.flatMap(createAuthorPaginatedRoute),
|
|
190
|
+
];
|
|
191
|
+
function createAuthorListRoute() {
|
|
192
|
+
return {
|
|
193
|
+
path: authorsListPath,
|
|
194
|
+
component: blogAuthorsListComponent,
|
|
195
|
+
exact: true,
|
|
196
|
+
modules: {
|
|
197
|
+
sidebar: sidebarModulePath,
|
|
198
|
+
},
|
|
199
|
+
props: {
|
|
200
|
+
authors: authors.map((author) => (0, props_1.toAuthorItemProp)({
|
|
201
|
+
author,
|
|
202
|
+
count: blogPostsByAuthorKey[author.key]?.length ?? 0,
|
|
203
|
+
})),
|
|
204
|
+
},
|
|
205
|
+
context: {
|
|
206
|
+
blogMetadata: blogMetadataModulePath,
|
|
207
|
+
},
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
function createAuthorPaginatedRoute(author) {
|
|
211
|
+
const authorBlogPosts = blogPostsByAuthorKey[author.key] ?? [];
|
|
212
|
+
if (!author.page) {
|
|
213
|
+
return [];
|
|
214
|
+
}
|
|
215
|
+
const pages = (0, blogUtils_1.paginateBlogPosts)({
|
|
216
|
+
blogPosts: authorBlogPosts,
|
|
217
|
+
basePageUrl: author.page.permalink,
|
|
218
|
+
blogDescription,
|
|
219
|
+
blogTitle,
|
|
220
|
+
pageBasePath: authorsBasePath,
|
|
221
|
+
postsPerPageOption: postsPerPage,
|
|
222
|
+
});
|
|
223
|
+
return pages.map(({ metadata, items }) => {
|
|
224
|
+
return {
|
|
225
|
+
path: metadata.permalink,
|
|
226
|
+
component: blogAuthorsPostsComponent,
|
|
227
|
+
exact: true,
|
|
228
|
+
modules: {
|
|
229
|
+
items: blogPostItemsModule(items),
|
|
230
|
+
sidebar: sidebarModulePath,
|
|
231
|
+
},
|
|
232
|
+
props: {
|
|
233
|
+
author: (0, props_1.toAuthorItemProp)({ author, count: authorBlogPosts.length }),
|
|
234
|
+
listMetadata: metadata,
|
|
235
|
+
},
|
|
236
|
+
context: {
|
|
237
|
+
blogMetadata: blogMetadataModulePath,
|
|
238
|
+
},
|
|
239
|
+
};
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
}
|
|
171
243
|
return [
|
|
172
244
|
...createBlogPostRoutes(),
|
|
173
245
|
...createBlogPostsPaginatedRoutes(),
|
|
174
246
|
...createTagsRoutes(),
|
|
175
247
|
...createArchiveRoute(),
|
|
248
|
+
...createAuthorsRoutes(),
|
|
176
249
|
];
|
|
177
250
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@docusaurus/plugin-content-blog",
|
|
3
|
-
"version": "0.0.0-
|
|
3
|
+
"version": "0.0.0-6014",
|
|
4
4
|
"description": "Blog plugin for Docusaurus.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "src/plugin-content-blog.d.ts",
|
|
@@ -31,14 +31,14 @@
|
|
|
31
31
|
},
|
|
32
32
|
"license": "MIT",
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@docusaurus/core": "0.0.0-
|
|
35
|
-
"@docusaurus/logger": "0.0.0-
|
|
36
|
-
"@docusaurus/mdx-loader": "0.0.0-
|
|
37
|
-
"@docusaurus/theme-common": "0.0.0-
|
|
38
|
-
"@docusaurus/types": "0.0.0-
|
|
39
|
-
"@docusaurus/utils": "0.0.0-
|
|
40
|
-
"@docusaurus/utils-common": "0.0.0-
|
|
41
|
-
"@docusaurus/utils-validation": "0.0.0-
|
|
34
|
+
"@docusaurus/core": "0.0.0-6014",
|
|
35
|
+
"@docusaurus/logger": "0.0.0-6014",
|
|
36
|
+
"@docusaurus/mdx-loader": "0.0.0-6014",
|
|
37
|
+
"@docusaurus/theme-common": "0.0.0-6014",
|
|
38
|
+
"@docusaurus/types": "0.0.0-6014",
|
|
39
|
+
"@docusaurus/utils": "0.0.0-6014",
|
|
40
|
+
"@docusaurus/utils-common": "0.0.0-6014",
|
|
41
|
+
"@docusaurus/utils-validation": "0.0.0-6014",
|
|
42
42
|
"cheerio": "^1.0.0-rc.12",
|
|
43
43
|
"feed": "^4.2.2",
|
|
44
44
|
"fs-extra": "^11.1.1",
|
|
@@ -61,5 +61,5 @@
|
|
|
61
61
|
"devDependencies": {
|
|
62
62
|
"@total-typescript/shoehorn": "^0.1.2"
|
|
63
63
|
},
|
|
64
|
-
"gitHead": "
|
|
64
|
+
"gitHead": "77581424d709d71c35dface5df45925e2851c2c8"
|
|
65
65
|
}
|