@docusaurus/plugin-content-blog 0.0.0-6012 → 0.0.0-6016
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/assets/atom.css +75 -0
- package/assets/atom.xsl +92 -0
- package/assets/rss.css +75 -0
- package/assets/rss.xsl +86 -0
- 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/feed.d.ts +3 -1
- package/lib/feed.js +67 -18
- package/lib/index.js +16 -2
- package/lib/options.d.ts +4 -0
- package/lib/options.js +87 -25
- package/lib/props.d.ts +5 -1
- package/lib/props.js +7 -0
- package/lib/routes.js +75 -2
- package/package.json +12 -11
- package/src/authors.ts +57 -111
- package/src/authorsMap.ts +171 -0
- package/src/blogUtils.ts +4 -7
- package/src/feed.ts +140 -17
- package/src/index.ts +24 -1
- package/src/options.ts +112 -32
- package/src/plugin-content-blog.d.ts +116 -12
- package/src/props.ts +15 -0
- package/src/routes.ts +97 -2
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/feed.d.ts
CHANGED
|
@@ -4,14 +4,16 @@
|
|
|
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 { BlogContentPaths } from './types';
|
|
7
8
|
import type { DocusaurusConfig, HtmlTags, LoadContext } from '@docusaurus/types';
|
|
8
9
|
import type { PluginOptions, BlogPost } from '@docusaurus/plugin-content-blog';
|
|
9
|
-
export declare function createBlogFeedFiles({ blogPosts: allBlogPosts, options, siteConfig, outDir, locale, }: {
|
|
10
|
+
export declare function createBlogFeedFiles({ blogPosts: allBlogPosts, options, siteConfig, outDir, locale, contentPaths, }: {
|
|
10
11
|
blogPosts: BlogPost[];
|
|
11
12
|
options: PluginOptions;
|
|
12
13
|
siteConfig: DocusaurusConfig;
|
|
13
14
|
outDir: string;
|
|
14
15
|
locale: string;
|
|
16
|
+
contentPaths: BlogContentPaths;
|
|
15
17
|
}): Promise<void>;
|
|
16
18
|
export declare function createFeedHtmlHeadTags({ context, options, }: {
|
|
17
19
|
context: LoadContext;
|
package/lib/feed.js
CHANGED
|
@@ -11,12 +11,12 @@ exports.createFeedHtmlHeadTags = createFeedHtmlHeadTags;
|
|
|
11
11
|
const tslib_1 = require("tslib");
|
|
12
12
|
const path_1 = tslib_1.__importDefault(require("path"));
|
|
13
13
|
const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
|
|
14
|
-
const logger_1 = tslib_1.__importDefault(require("@docusaurus/logger"));
|
|
15
14
|
const feed_1 = require("feed");
|
|
16
15
|
const srcset = tslib_1.__importStar(require("srcset"));
|
|
17
16
|
const utils_1 = require("@docusaurus/utils");
|
|
18
17
|
const utils_common_1 = require("@docusaurus/utils-common");
|
|
19
18
|
const cheerio_1 = require("cheerio");
|
|
19
|
+
const logger_1 = tslib_1.__importDefault(require("@docusaurus/logger"));
|
|
20
20
|
async function generateBlogFeed({ blogPosts, options, siteConfig, outDir, locale, }) {
|
|
21
21
|
if (!blogPosts.length) {
|
|
22
22
|
return null;
|
|
@@ -106,25 +106,72 @@ async function defaultCreateFeedItems({ blogPosts, siteConfig, outDir, }) {
|
|
|
106
106
|
return feedItem;
|
|
107
107
|
}));
|
|
108
108
|
}
|
|
109
|
-
async function
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
}
|
|
121
|
-
|
|
109
|
+
async function resolveXsltFilePaths({ xsltFilePath, contentPaths, }) {
|
|
110
|
+
const xsltAbsolutePath = path_1.default.isAbsolute(xsltFilePath)
|
|
111
|
+
? xsltFilePath
|
|
112
|
+
: (await (0, utils_1.getDataFilePath)({ filePath: xsltFilePath, contentPaths })) ??
|
|
113
|
+
path_1.default.resolve(contentPaths.contentPath, xsltFilePath);
|
|
114
|
+
if (!(await fs_extra_1.default.pathExists(xsltAbsolutePath))) {
|
|
115
|
+
throw new Error(logger_1.default.interpolate `Blog feed XSLT file not found at path=${path_1.default.relative(process.cwd(), xsltAbsolutePath)}`);
|
|
116
|
+
}
|
|
117
|
+
const parsedPath = path_1.default.parse(xsltAbsolutePath);
|
|
118
|
+
const cssAbsolutePath = path_1.default.resolve(parsedPath.dir, `${parsedPath.name}.css`);
|
|
119
|
+
if (!(await fs_extra_1.default.pathExists(xsltAbsolutePath))) {
|
|
120
|
+
throw new Error(logger_1.default.interpolate `Blog feed XSLT file was found at path=${path_1.default.relative(process.cwd(), xsltAbsolutePath)}
|
|
121
|
+
But its expected co-located CSS file could not be found at path=${path_1.default.relative(process.cwd(), cssAbsolutePath)}
|
|
122
|
+
If you want to provide a custom XSLT file, you must provide a CSS file with the exact same name.`);
|
|
123
|
+
}
|
|
124
|
+
return { xsltAbsolutePath, cssAbsolutePath };
|
|
125
|
+
}
|
|
126
|
+
async function generateXsltFiles({ xsltFilePath, generatePath, contentPaths, }) {
|
|
127
|
+
const { xsltAbsolutePath, cssAbsolutePath } = await resolveXsltFilePaths({
|
|
128
|
+
xsltFilePath,
|
|
129
|
+
contentPaths,
|
|
130
|
+
});
|
|
131
|
+
const xsltOutputPath = path_1.default.join(generatePath, path_1.default.basename(xsltAbsolutePath));
|
|
132
|
+
const cssOutputPath = path_1.default.join(generatePath, path_1.default.basename(cssAbsolutePath));
|
|
133
|
+
await fs_extra_1.default.copy(xsltAbsolutePath, xsltOutputPath);
|
|
134
|
+
await fs_extra_1.default.copy(cssAbsolutePath, cssOutputPath);
|
|
135
|
+
}
|
|
136
|
+
// This modifies the XML feed content to add a relative href to the XSLT file
|
|
137
|
+
// Good enough for now: we probably don't need a full XML parser just for that
|
|
138
|
+
// See also https://darekkay.com/blog/rss-styling/
|
|
139
|
+
function injectXslt({ feedContent, xsltFilePath, }) {
|
|
140
|
+
return feedContent.replace('<?xml version="1.0" encoding="utf-8"?>', `<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="${path_1.default.basename(xsltFilePath)}"?>`);
|
|
141
|
+
}
|
|
142
|
+
const FeedConfigs = {
|
|
143
|
+
rss: {
|
|
144
|
+
outputFileName: 'rss.xml',
|
|
145
|
+
getContent: (feed) => feed.rss2(),
|
|
146
|
+
getXsltFilePath: (xslt) => xslt.rss,
|
|
147
|
+
},
|
|
148
|
+
atom: {
|
|
149
|
+
outputFileName: 'atom.xml',
|
|
150
|
+
getContent: (feed) => feed.atom1(),
|
|
151
|
+
getXsltFilePath: (xslt) => xslt.atom,
|
|
152
|
+
},
|
|
153
|
+
json: {
|
|
154
|
+
outputFileName: 'feed.json',
|
|
155
|
+
getContent: (feed) => feed.json1(),
|
|
156
|
+
getXsltFilePath: () => null,
|
|
157
|
+
},
|
|
158
|
+
};
|
|
159
|
+
async function createBlogFeedFile({ feed, feedType, generatePath, feedOptions, contentPaths, }) {
|
|
122
160
|
try {
|
|
123
|
-
|
|
161
|
+
const feedConfig = FeedConfigs[feedType];
|
|
162
|
+
let feedContent = feedConfig.getContent(feed);
|
|
163
|
+
const xsltFilePath = feedConfig.getXsltFilePath(feedOptions.xslt);
|
|
164
|
+
if (xsltFilePath) {
|
|
165
|
+
await generateXsltFiles({ xsltFilePath, contentPaths, generatePath });
|
|
166
|
+
feedContent = injectXslt({ feedContent, xsltFilePath });
|
|
167
|
+
}
|
|
168
|
+
const outputPath = path_1.default.join(generatePath, feedConfig.outputFileName);
|
|
169
|
+
await fs_extra_1.default.outputFile(outputPath, feedContent);
|
|
124
170
|
}
|
|
125
171
|
catch (err) {
|
|
126
|
-
|
|
127
|
-
|
|
172
|
+
throw new Error(`Generating ${feedType} feed failed.`, {
|
|
173
|
+
cause: err,
|
|
174
|
+
});
|
|
128
175
|
}
|
|
129
176
|
}
|
|
130
177
|
function shouldBeInFeed(blogPost) {
|
|
@@ -132,7 +179,7 @@ function shouldBeInFeed(blogPost) {
|
|
|
132
179
|
blogPost.metadata.frontMatter.unlisted;
|
|
133
180
|
return !excluded;
|
|
134
181
|
}
|
|
135
|
-
async function createBlogFeedFiles({ blogPosts: allBlogPosts, options, siteConfig, outDir, locale, }) {
|
|
182
|
+
async function createBlogFeedFiles({ blogPosts: allBlogPosts, options, siteConfig, outDir, locale, contentPaths, }) {
|
|
136
183
|
const blogPosts = allBlogPosts.filter(shouldBeInFeed);
|
|
137
184
|
const feed = await generateBlogFeed({
|
|
138
185
|
blogPosts,
|
|
@@ -149,6 +196,8 @@ async function createBlogFeedFiles({ blogPosts: allBlogPosts, options, siteConfi
|
|
|
149
196
|
feed,
|
|
150
197
|
feedType,
|
|
151
198
|
generatePath: path_1.default.join(outDir, options.routeBasePath),
|
|
199
|
+
feedOptions: options.feedOptions,
|
|
200
|
+
contentPaths,
|
|
152
201
|
})));
|
|
153
202
|
}
|
|
154
203
|
function createFeedHtmlHeadTags({ context, options, }) {
|
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 }) {
|
|
@@ -253,6 +266,7 @@ async function pluginContentBlog(context, options) {
|
|
|
253
266
|
outDir,
|
|
254
267
|
siteConfig,
|
|
255
268
|
locale: currentLocale,
|
|
269
|
+
contentPaths,
|
|
256
270
|
});
|
|
257
271
|
},
|
|
258
272
|
injectHtmlTags({ content }) {
|
package/lib/options.d.ts
CHANGED
|
@@ -7,4 +7,8 @@
|
|
|
7
7
|
import type { PluginOptions, Options } from '@docusaurus/plugin-content-blog';
|
|
8
8
|
import type { OptionValidationContext } from '@docusaurus/types';
|
|
9
9
|
export declare const DEFAULT_OPTIONS: PluginOptions;
|
|
10
|
+
export declare const XSLTBuiltInPaths: {
|
|
11
|
+
rss: string;
|
|
12
|
+
atom: string;
|
|
13
|
+
};
|
|
10
14
|
export declare function validateOptions({ validate, options, }: OptionValidationContext<Options | undefined, PluginOptions>): PluginOptions;
|
package/lib/options.js
CHANGED
|
@@ -6,12 +6,22 @@
|
|
|
6
6
|
* LICENSE file in the root directory of this source tree.
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.DEFAULT_OPTIONS = void 0;
|
|
9
|
+
exports.XSLTBuiltInPaths = exports.DEFAULT_OPTIONS = void 0;
|
|
10
10
|
exports.validateOptions = validateOptions;
|
|
11
|
+
const tslib_1 = require("tslib");
|
|
12
|
+
const path_1 = tslib_1.__importDefault(require("path"));
|
|
11
13
|
const utils_validation_1 = require("@docusaurus/utils-validation");
|
|
12
14
|
const utils_1 = require("@docusaurus/utils");
|
|
13
15
|
exports.DEFAULT_OPTIONS = {
|
|
14
|
-
feedOptions: {
|
|
16
|
+
feedOptions: {
|
|
17
|
+
type: ['rss', 'atom'],
|
|
18
|
+
copyright: '',
|
|
19
|
+
limit: 20,
|
|
20
|
+
xslt: {
|
|
21
|
+
rss: null,
|
|
22
|
+
atom: null,
|
|
23
|
+
},
|
|
24
|
+
},
|
|
15
25
|
beforeDefaultRehypePlugins: [],
|
|
16
26
|
beforeDefaultRemarkPlugins: [],
|
|
17
27
|
admonitions: true,
|
|
@@ -22,6 +32,8 @@ exports.DEFAULT_OPTIONS = {
|
|
|
22
32
|
showReadingTime: true,
|
|
23
33
|
blogTagsPostsComponent: '@theme/BlogTagsPostsPage',
|
|
24
34
|
blogTagsListComponent: '@theme/BlogTagsListPage',
|
|
35
|
+
blogAuthorsPostsComponent: '@theme/Blog/Pages/BlogAuthorsPostsPage',
|
|
36
|
+
blogAuthorsListComponent: '@theme/Blog/Pages/BlogAuthorsListPage',
|
|
25
37
|
blogPostComponent: '@theme/BlogPostPage',
|
|
26
38
|
blogListComponent: '@theme/BlogListPage',
|
|
27
39
|
blogArchiveComponent: '@theme/BlogArchivePage',
|
|
@@ -46,8 +58,75 @@ exports.DEFAULT_OPTIONS = {
|
|
|
46
58
|
processBlogPosts: async () => undefined,
|
|
47
59
|
onInlineTags: 'warn',
|
|
48
60
|
tags: undefined,
|
|
61
|
+
authorsBasePath: 'authors',
|
|
49
62
|
onInlineAuthors: 'warn',
|
|
50
63
|
};
|
|
64
|
+
exports.XSLTBuiltInPaths = {
|
|
65
|
+
rss: path_1.default.resolve(__dirname, '..', 'assets', 'rss.xsl'),
|
|
66
|
+
atom: path_1.default.resolve(__dirname, '..', 'assets', 'atom.xsl'),
|
|
67
|
+
};
|
|
68
|
+
function normalizeXsltOption(option, type) {
|
|
69
|
+
if (typeof option === 'string') {
|
|
70
|
+
return option;
|
|
71
|
+
}
|
|
72
|
+
if (option === true) {
|
|
73
|
+
return exports.XSLTBuiltInPaths[type];
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
function createXSLTFilePathSchema(type) {
|
|
78
|
+
return utils_validation_1.Joi.alternatives()
|
|
79
|
+
.try(utils_validation_1.Joi.string().required(), utils_validation_1.Joi.boolean()
|
|
80
|
+
.allow(null, () => undefined)
|
|
81
|
+
.custom((val) => normalizeXsltOption(val, type)))
|
|
82
|
+
.optional()
|
|
83
|
+
.default(null);
|
|
84
|
+
}
|
|
85
|
+
const FeedXSLTOptionsSchema = utils_validation_1.Joi.alternatives()
|
|
86
|
+
.try(utils_validation_1.Joi.object({
|
|
87
|
+
rss: createXSLTFilePathSchema('rss'),
|
|
88
|
+
atom: createXSLTFilePathSchema('atom'),
|
|
89
|
+
}).required(), utils_validation_1.Joi.boolean()
|
|
90
|
+
.allow(null, () => undefined)
|
|
91
|
+
.custom((val) => ({
|
|
92
|
+
rss: normalizeXsltOption(val, 'rss'),
|
|
93
|
+
atom: normalizeXsltOption(val, 'atom'),
|
|
94
|
+
})))
|
|
95
|
+
.optional()
|
|
96
|
+
.custom((val) => {
|
|
97
|
+
if (val === null) {
|
|
98
|
+
return {
|
|
99
|
+
rss: null,
|
|
100
|
+
atom: null,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
return val;
|
|
104
|
+
})
|
|
105
|
+
.default(exports.DEFAULT_OPTIONS.feedOptions.xslt);
|
|
106
|
+
const FeedOptionsSchema = utils_validation_1.Joi.object({
|
|
107
|
+
type: utils_validation_1.Joi.alternatives()
|
|
108
|
+
.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'), {
|
|
109
|
+
then: utils_validation_1.Joi.custom((val) => val === 'all' ? ['rss', 'atom', 'json'] : [val]),
|
|
110
|
+
}))
|
|
111
|
+
.allow(null)
|
|
112
|
+
.default(exports.DEFAULT_OPTIONS.feedOptions.type),
|
|
113
|
+
xslt: FeedXSLTOptionsSchema,
|
|
114
|
+
title: utils_validation_1.Joi.string().allow(''),
|
|
115
|
+
description: utils_validation_1.Joi.string().allow(''),
|
|
116
|
+
// Only add default value when user actually wants a feed (type is not null)
|
|
117
|
+
copyright: utils_validation_1.Joi.when('type', {
|
|
118
|
+
is: utils_validation_1.Joi.any().valid(null),
|
|
119
|
+
then: utils_validation_1.Joi.string().optional(),
|
|
120
|
+
otherwise: utils_validation_1.Joi.string()
|
|
121
|
+
.allow('')
|
|
122
|
+
.default(exports.DEFAULT_OPTIONS.feedOptions.copyright),
|
|
123
|
+
}),
|
|
124
|
+
language: utils_validation_1.Joi.string(),
|
|
125
|
+
createFeedItems: utils_validation_1.Joi.function(),
|
|
126
|
+
limit: utils_validation_1.Joi.alternatives()
|
|
127
|
+
.try(utils_validation_1.Joi.number(), utils_validation_1.Joi.valid(null), utils_validation_1.Joi.valid(false))
|
|
128
|
+
.default(exports.DEFAULT_OPTIONS.feedOptions.limit),
|
|
129
|
+
}).default(exports.DEFAULT_OPTIONS.feedOptions);
|
|
51
130
|
const PluginOptionSchema = utils_validation_1.Joi.object({
|
|
52
131
|
path: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.path),
|
|
53
132
|
archiveBasePath: utils_validation_1.Joi.string()
|
|
@@ -65,6 +144,8 @@ const PluginOptionSchema = utils_validation_1.Joi.object({
|
|
|
65
144
|
blogPostComponent: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.blogPostComponent),
|
|
66
145
|
blogTagsListComponent: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.blogTagsListComponent),
|
|
67
146
|
blogTagsPostsComponent: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.blogTagsPostsComponent),
|
|
147
|
+
blogAuthorsPostsComponent: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.blogAuthorsPostsComponent),
|
|
148
|
+
blogAuthorsListComponent: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.blogAuthorsListComponent),
|
|
68
149
|
blogArchiveComponent: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.blogArchiveComponent),
|
|
69
150
|
blogTitle: utils_validation_1.Joi.string().allow('').default(exports.DEFAULT_OPTIONS.blogTitle),
|
|
70
151
|
blogDescription: utils_validation_1.Joi.string()
|
|
@@ -84,29 +165,7 @@ const PluginOptionSchema = utils_validation_1.Joi.object({
|
|
|
84
165
|
truncateMarker: utils_validation_1.Joi.object().default(exports.DEFAULT_OPTIONS.truncateMarker),
|
|
85
166
|
beforeDefaultRemarkPlugins: utils_validation_1.RemarkPluginsSchema.default(exports.DEFAULT_OPTIONS.beforeDefaultRemarkPlugins),
|
|
86
167
|
beforeDefaultRehypePlugins: utils_validation_1.RehypePluginsSchema.default(exports.DEFAULT_OPTIONS.beforeDefaultRehypePlugins),
|
|
87
|
-
feedOptions:
|
|
88
|
-
type: utils_validation_1.Joi.alternatives()
|
|
89
|
-
.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'), {
|
|
90
|
-
then: utils_validation_1.Joi.custom((val) => val === 'all' ? ['rss', 'atom', 'json'] : [val]),
|
|
91
|
-
}))
|
|
92
|
-
.allow(null)
|
|
93
|
-
.default(exports.DEFAULT_OPTIONS.feedOptions.type),
|
|
94
|
-
title: utils_validation_1.Joi.string().allow(''),
|
|
95
|
-
description: utils_validation_1.Joi.string().allow(''),
|
|
96
|
-
// Only add default value when user actually wants a feed (type is not null)
|
|
97
|
-
copyright: utils_validation_1.Joi.when('type', {
|
|
98
|
-
is: utils_validation_1.Joi.any().valid(null),
|
|
99
|
-
then: utils_validation_1.Joi.string().optional(),
|
|
100
|
-
otherwise: utils_validation_1.Joi.string()
|
|
101
|
-
.allow('')
|
|
102
|
-
.default(exports.DEFAULT_OPTIONS.feedOptions.copyright),
|
|
103
|
-
}),
|
|
104
|
-
language: utils_validation_1.Joi.string(),
|
|
105
|
-
createFeedItems: utils_validation_1.Joi.function(),
|
|
106
|
-
limit: utils_validation_1.Joi.alternatives()
|
|
107
|
-
.try(utils_validation_1.Joi.number(), utils_validation_1.Joi.valid(null), utils_validation_1.Joi.valid(false))
|
|
108
|
-
.default(exports.DEFAULT_OPTIONS.feedOptions.limit),
|
|
109
|
-
}).default(exports.DEFAULT_OPTIONS.feedOptions),
|
|
168
|
+
feedOptions: FeedOptionsSchema,
|
|
110
169
|
authorsMapPath: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.authorsMapPath),
|
|
111
170
|
readingTime: utils_validation_1.Joi.function().default(() => exports.DEFAULT_OPTIONS.readingTime),
|
|
112
171
|
sortPosts: utils_validation_1.Joi.string()
|
|
@@ -124,6 +183,9 @@ const PluginOptionSchema = utils_validation_1.Joi.object({
|
|
|
124
183
|
.disallow('')
|
|
125
184
|
.allow(null, false)
|
|
126
185
|
.default(() => exports.DEFAULT_OPTIONS.tags),
|
|
186
|
+
authorsBasePath: utils_validation_1.Joi.string()
|
|
187
|
+
.default(exports.DEFAULT_OPTIONS.authorsBasePath)
|
|
188
|
+
.disallow(''),
|
|
127
189
|
onInlineAuthors: utils_validation_1.Joi.string()
|
|
128
190
|
.equal('ignore', 'log', 'warn', 'throw')
|
|
129
191
|
.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-6016",
|
|
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-6016",
|
|
35
|
+
"@docusaurus/logger": "0.0.0-6016",
|
|
36
|
+
"@docusaurus/mdx-loader": "0.0.0-6016",
|
|
37
|
+
"@docusaurus/theme-common": "0.0.0-6016",
|
|
38
|
+
"@docusaurus/types": "0.0.0-6016",
|
|
39
|
+
"@docusaurus/utils": "0.0.0-6016",
|
|
40
|
+
"@docusaurus/utils-common": "0.0.0-6016",
|
|
41
|
+
"@docusaurus/utils-validation": "0.0.0-6016",
|
|
42
42
|
"cheerio": "^1.0.0-rc.12",
|
|
43
43
|
"feed": "^4.2.2",
|
|
44
44
|
"fs-extra": "^11.1.1",
|
|
@@ -59,7 +59,8 @@
|
|
|
59
59
|
"node": ">=18.0"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
|
-
"@total-typescript/shoehorn": "^0.1.2"
|
|
62
|
+
"@total-typescript/shoehorn": "^0.1.2",
|
|
63
|
+
"tree-node-cli": "^1.6.0"
|
|
63
64
|
},
|
|
64
|
-
"gitHead": "
|
|
65
|
+
"gitHead": "c51435db0c58b94667da1c745f1635de65240c63"
|
|
65
66
|
}
|