@docusaurus/plugin-content-blog 3.4.0 → 3.5.1

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.
Files changed (59) hide show
  1. package/assets/atom.css +75 -0
  2. package/assets/atom.xsl +92 -0
  3. package/assets/rss.css +75 -0
  4. package/assets/rss.xsl +86 -0
  5. package/lib/authors.d.ts +9 -11
  6. package/lib/authors.js +42 -64
  7. package/lib/authorsMap.d.ts +23 -0
  8. package/lib/authorsMap.js +116 -0
  9. package/lib/authorsProblems.d.ts +21 -0
  10. package/lib/authorsProblems.js +51 -0
  11. package/lib/authorsSocials.d.ts +10 -0
  12. package/lib/authorsSocials.js +48 -0
  13. package/lib/blogUtils.d.ts +6 -3
  14. package/lib/blogUtils.js +29 -14
  15. package/lib/client/contexts.d.ts +33 -0
  16. package/lib/client/contexts.js +54 -0
  17. package/lib/client/index.d.ts +3 -3
  18. package/lib/client/index.js +3 -9
  19. package/lib/client/sidebarUtils.d.ts +21 -0
  20. package/lib/client/sidebarUtils.js +49 -0
  21. package/lib/client/sidebarUtils.test.d.ts +7 -0
  22. package/lib/client/sidebarUtils.test.js +43 -0
  23. package/lib/client/structuredDataUtils.d.ts +10 -0
  24. package/lib/client/structuredDataUtils.js +122 -0
  25. package/lib/feed.d.ts +3 -2
  26. package/lib/feed.js +69 -21
  27. package/lib/frontMatter.d.ts +0 -1
  28. package/lib/frontMatter.js +3 -2
  29. package/lib/index.d.ts +0 -1
  30. package/lib/index.js +23 -4
  31. package/lib/markdownLoader.js +1 -1
  32. package/lib/options.d.ts +4 -1
  33. package/lib/options.js +98 -26
  34. package/lib/props.d.ts +9 -2
  35. package/lib/props.js +21 -3
  36. package/lib/remark/footnoteIDFixer.js +1 -1
  37. package/lib/routes.d.ts +0 -1
  38. package/lib/routes.js +82 -14
  39. package/lib/translations.d.ts +0 -1
  40. package/lib/translations.js +2 -3
  41. package/package.json +14 -11
  42. package/src/authors.ts +56 -93
  43. package/src/authorsMap.ts +171 -0
  44. package/src/authorsProblems.ts +72 -0
  45. package/src/authorsSocials.ts +64 -0
  46. package/src/blogUtils.ts +34 -7
  47. package/src/client/contexts.tsx +95 -0
  48. package/src/client/index.tsx +24 -0
  49. package/src/client/sidebarUtils.test.ts +52 -0
  50. package/src/client/sidebarUtils.tsx +85 -0
  51. package/src/client/structuredDataUtils.ts +178 -0
  52. package/src/feed.ts +140 -17
  53. package/src/frontMatter.ts +2 -0
  54. package/src/index.ts +31 -1
  55. package/src/options.ts +123 -32
  56. package/src/plugin-content-blog.d.ts +150 -12
  57. package/src/props.ts +39 -1
  58. package/src/routes.ts +102 -12
  59. package/src/client/index.ts +0 -20
package/lib/feed.js CHANGED
@@ -6,16 +6,17 @@
6
6
  * LICENSE file in the root directory of this source tree.
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.createFeedHtmlHeadTags = exports.createBlogFeedFiles = void 0;
9
+ exports.createBlogFeedFiles = createBlogFeedFiles;
10
+ exports.createFeedHtmlHeadTags = createFeedHtmlHeadTags;
10
11
  const tslib_1 = require("tslib");
11
12
  const path_1 = tslib_1.__importDefault(require("path"));
12
13
  const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
13
- const logger_1 = tslib_1.__importDefault(require("@docusaurus/logger"));
14
14
  const feed_1 = require("feed");
15
15
  const srcset = tslib_1.__importStar(require("srcset"));
16
16
  const utils_1 = require("@docusaurus/utils");
17
17
  const utils_common_1 = require("@docusaurus/utils-common");
18
18
  const cheerio_1 = require("cheerio");
19
+ const logger_1 = tslib_1.__importDefault(require("@docusaurus/logger"));
19
20
  async function generateBlogFeed({ blogPosts, options, siteConfig, outDir, locale, }) {
20
21
  if (!blogPosts.length) {
21
22
  return null;
@@ -105,25 +106,72 @@ async function defaultCreateFeedItems({ blogPosts, siteConfig, outDir, }) {
105
106
  return feedItem;
106
107
  }));
107
108
  }
108
- async function createBlogFeedFile({ feed, feedType, generatePath, }) {
109
- const [feedContent, feedPath] = (() => {
110
- switch (feedType) {
111
- case 'rss':
112
- return [feed.rss2(), 'rss.xml'];
113
- case 'json':
114
- return [feed.json1(), 'feed.json'];
115
- case 'atom':
116
- return [feed.atom1(), 'atom.xml'];
117
- default:
118
- throw new Error(`Feed type ${feedType} not supported.`);
119
- }
120
- })();
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, }) {
121
160
  try {
122
- await fs_extra_1.default.outputFile(path_1.default.join(generatePath, feedPath), feedContent);
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);
123
170
  }
124
171
  catch (err) {
125
- logger_1.default.error(`Generating ${feedType} feed failed.`);
126
- throw err;
172
+ throw new Error(`Generating ${feedType} feed failed.`, {
173
+ cause: err,
174
+ });
127
175
  }
128
176
  }
129
177
  function shouldBeInFeed(blogPost) {
@@ -131,7 +179,7 @@ function shouldBeInFeed(blogPost) {
131
179
  blogPost.metadata.frontMatter.unlisted;
132
180
  return !excluded;
133
181
  }
134
- async function createBlogFeedFiles({ blogPosts: allBlogPosts, options, siteConfig, outDir, locale, }) {
182
+ async function createBlogFeedFiles({ blogPosts: allBlogPosts, options, siteConfig, outDir, locale, contentPaths, }) {
135
183
  const blogPosts = allBlogPosts.filter(shouldBeInFeed);
136
184
  const feed = await generateBlogFeed({
137
185
  blogPosts,
@@ -148,9 +196,10 @@ async function createBlogFeedFiles({ blogPosts: allBlogPosts, options, siteConfi
148
196
  feed,
149
197
  feedType,
150
198
  generatePath: path_1.default.join(outDir, options.routeBasePath),
199
+ feedOptions: options.feedOptions,
200
+ contentPaths,
151
201
  })));
152
202
  }
153
- exports.createBlogFeedFiles = createBlogFeedFiles;
154
203
  function createFeedHtmlHeadTags({ context, options, }) {
155
204
  const feedTypes = options.feedOptions.type;
156
205
  if (!feedTypes) {
@@ -193,4 +242,3 @@ function createFeedHtmlHeadTags({ context, options, }) {
193
242
  });
194
243
  return headTags;
195
244
  }
196
- exports.createFeedHtmlHeadTags = createFeedHtmlHeadTags;
@@ -1,4 +1,3 @@
1
- /// <reference path="../src/plugin-content-blog.d.ts" />
2
1
  import type { BlogPostFrontMatter } from '@docusaurus/plugin-content-blog';
3
2
  export declare function validateBlogPostFrontMatter(frontMatter: {
4
3
  [key: string]: unknown;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.validateBlogPostFrontMatter = void 0;
3
+ exports.validateBlogPostFrontMatter = validateBlogPostFrontMatter;
4
4
  /**
5
5
  * Copyright (c) Facebook, Inc. and its affiliates.
6
6
  *
@@ -8,12 +8,14 @@ exports.validateBlogPostFrontMatter = void 0;
8
8
  * LICENSE file in the root directory of this source tree.
9
9
  */
10
10
  const utils_validation_1 = require("@docusaurus/utils-validation");
11
+ const authorsSocials_1 = require("./authorsSocials");
11
12
  const BlogPostFrontMatterAuthorSchema = utils_validation_1.JoiFrontMatter.object({
12
13
  key: utils_validation_1.JoiFrontMatter.string(),
13
14
  name: utils_validation_1.JoiFrontMatter.string(),
14
15
  title: utils_validation_1.JoiFrontMatter.string(),
15
16
  url: utils_validation_1.URISchema,
16
17
  imageURL: utils_validation_1.JoiFrontMatter.string(),
18
+ socials: authorsSocials_1.AuthorSocialsSchema,
17
19
  })
18
20
  .or('key', 'name', 'imageURL')
19
21
  .rename('image_url', 'imageURL', { alias: true });
@@ -61,4 +63,3 @@ const BlogFrontMatterSchema = utils_validation_1.JoiFrontMatter.object({
61
63
  function validateBlogPostFrontMatter(frontMatter) {
62
64
  return (0, utils_validation_1.validateFrontMatter)(frontMatter, BlogFrontMatterSchema);
63
65
  }
64
- exports.validateBlogPostFrontMatter = validateBlogPostFrontMatter;
package/lib/index.d.ts CHANGED
@@ -4,7 +4,6 @@
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
- /// <reference path="../src/plugin-content-blog.d.ts" />
8
7
  import type { LoadContext, Plugin } from '@docusaurus/types';
9
8
  import type { PluginOptions, BlogContent } from '@docusaurus/plugin-content-blog';
10
9
  export default function pluginContentBlog(context: LoadContext, options: PluginOptions): Promise<Plugin<BlogContent>>;
package/lib/index.js CHANGED
@@ -7,6 +7,7 @@
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.validateOptions = void 0;
10
+ exports.default = pluginContentBlog;
10
11
  const tslib_1 = require("tslib");
11
12
  const path_1 = tslib_1.__importDefault(require("path"));
12
13
  const logger_1 = tslib_1.__importDefault(require("@docusaurus/logger"));
@@ -17,6 +18,7 @@ const footnoteIDFixer_1 = tslib_1.__importDefault(require("./remark/footnoteIDFi
17
18
  const translations_1 = require("./translations");
18
19
  const feed_1 = require("./feed");
19
20
  const routes_1 = require("./routes");
21
+ const authorsMap_1 = require("./authorsMap");
20
22
  const PluginName = 'docusaurus-plugin-content-blog';
21
23
  // TODO this is bad, we should have a better way to do this (new lifecycle?)
22
24
  // The source to permalink is currently a mutable map passed to the mdx loader
@@ -87,14 +89,28 @@ async function pluginContentBlog(context, options) {
87
89
  },
88
90
  // Fetches blog contents and returns metadata for the necessary routes.
89
91
  async loadContent() {
90
- const { postsPerPage: postsPerPageOption, routeBasePath, tagsBasePath, blogDescription, blogTitle, blogSidebarTitle, pageBasePath, } = options;
92
+ const { postsPerPage: postsPerPageOption, routeBasePath, tagsBasePath, blogDescription, blogTitle, blogSidebarTitle, pageBasePath, authorsBasePath, authorsMapPath, } = options;
91
93
  const baseBlogUrl = (0, utils_1.normalizeUrl)([baseUrl, routeBasePath]);
92
94
  const blogTagsListPath = (0, utils_1.normalizeUrl)([baseBlogUrl, tagsBasePath]);
93
- let blogPosts = await (0, blogUtils_1.generateBlogPosts)(contentPaths, context, options);
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);
94
106
  blogPosts = await (0, blogUtils_1.applyProcessBlogPosts)({
95
107
  blogPosts,
96
108
  processBlogPosts: options.processBlogPosts,
97
109
  });
110
+ (0, blogUtils_1.reportUntruncatedBlogPosts)({
111
+ blogPosts,
112
+ onUntruncatedBlogPosts: options.onUntruncatedBlogPosts,
113
+ });
98
114
  const listedBlogPosts = blogPosts.filter(blogUtils_1.shouldBeListed);
99
115
  if (!blogPosts.length) {
100
116
  return {
@@ -103,6 +119,7 @@ async function pluginContentBlog(context, options) {
103
119
  blogListPaginated: [],
104
120
  blogTags: {},
105
121
  blogTagsListPath,
122
+ authorsMap,
106
123
  };
107
124
  }
108
125
  // Collocate next and prev metadata.
@@ -145,6 +162,7 @@ async function pluginContentBlog(context, options) {
145
162
  blogListPaginated,
146
163
  blogTags,
147
164
  blogTagsListPath,
165
+ authorsMap,
148
166
  };
149
167
  },
150
168
  async contentLoaded({ content, actions }) {
@@ -161,13 +179,14 @@ async function pluginContentBlog(context, options) {
161
179
  return (0, translations_1.translateContent)(content, translationFiles);
162
180
  },
163
181
  configureWebpack() {
164
- const { admonitions, rehypePlugins, remarkPlugins, truncateMarker, beforeDefaultRemarkPlugins, beforeDefaultRehypePlugins, } = options;
182
+ const { admonitions, rehypePlugins, remarkPlugins, recmaPlugins, truncateMarker, beforeDefaultRemarkPlugins, beforeDefaultRehypePlugins, } = options;
165
183
  const contentDirs = (0, utils_1.getContentPathList)(contentPaths);
166
184
  function createMDXLoader() {
167
185
  const loaderOptions = {
168
186
  admonitions,
169
187
  remarkPlugins,
170
188
  rehypePlugins,
189
+ recmaPlugins,
171
190
  beforeDefaultRemarkPlugins: [
172
191
  footnoteIDFixer_1.default,
173
192
  ...beforeDefaultRemarkPlugins,
@@ -251,6 +270,7 @@ async function pluginContentBlog(context, options) {
251
270
  outDir,
252
271
  siteConfig,
253
272
  locale: currentLocale,
273
+ contentPaths,
254
274
  });
255
275
  },
256
276
  injectHtmlTags({ content }) {
@@ -263,6 +283,5 @@ async function pluginContentBlog(context, options) {
263
283
  },
264
284
  };
265
285
  }
266
- exports.default = pluginContentBlog;
267
286
  var options_1 = require("./options");
268
287
  Object.defineProperty(exports, "validateOptions", { enumerable: true, get: function () { return options_1.validateOptions; } });
@@ -6,6 +6,7 @@
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 = markdownLoader;
9
10
  const blogUtils_1 = require("./blogUtils");
10
11
  function markdownLoader(source) {
11
12
  const fileString = source;
@@ -23,4 +24,3 @@ function markdownLoader(source) {
23
24
  }
24
25
  return callback(null, finalContent);
25
26
  }
26
- exports.default = markdownLoader;
package/lib/options.d.ts CHANGED
@@ -4,8 +4,11 @@
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
- /// <reference path="../src/plugin-content-blog.d.ts" />
8
7
  import type { PluginOptions, Options } from '@docusaurus/plugin-content-blog';
9
8
  import type { OptionValidationContext } from '@docusaurus/types';
10
9
  export declare const DEFAULT_OPTIONS: PluginOptions;
10
+ export declare const XSLTBuiltInPaths: {
11
+ rss: string;
12
+ atom: string;
13
+ };
11
14
  export declare function validateOptions({ validate, options, }: OptionValidationContext<Options | undefined, PluginOptions>): PluginOptions;
package/lib/options.js CHANGED
@@ -6,20 +6,34 @@
6
6
  * LICENSE file in the root directory of this source tree.
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.validateOptions = exports.DEFAULT_OPTIONS = void 0;
9
+ exports.XSLTBuiltInPaths = exports.DEFAULT_OPTIONS = void 0;
10
+ exports.validateOptions = validateOptions;
11
+ const tslib_1 = require("tslib");
12
+ const path_1 = tslib_1.__importDefault(require("path"));
10
13
  const utils_validation_1 = require("@docusaurus/utils-validation");
11
14
  const utils_1 = require("@docusaurus/utils");
12
15
  exports.DEFAULT_OPTIONS = {
13
- feedOptions: { type: ['rss', 'atom'], copyright: '', limit: 20 },
16
+ feedOptions: {
17
+ type: ['rss', 'atom'],
18
+ copyright: '',
19
+ limit: 20,
20
+ xslt: {
21
+ rss: null,
22
+ atom: null,
23
+ },
24
+ },
14
25
  beforeDefaultRehypePlugins: [],
15
26
  beforeDefaultRemarkPlugins: [],
16
27
  admonitions: true,
17
28
  truncateMarker: /<!--\s*truncate\s*-->|\{\/\*\s*truncate\s*\*\/\}/,
18
29
  rehypePlugins: [],
19
30
  remarkPlugins: [],
31
+ recmaPlugins: [],
20
32
  showReadingTime: true,
21
33
  blogTagsPostsComponent: '@theme/BlogTagsPostsPage',
22
34
  blogTagsListComponent: '@theme/BlogTagsListPage',
35
+ blogAuthorsPostsComponent: '@theme/Blog/Pages/BlogAuthorsPostsPage',
36
+ blogAuthorsListComponent: '@theme/Blog/Pages/BlogAuthorsListPage',
23
37
  blogPostComponent: '@theme/BlogPostPage',
24
38
  blogListComponent: '@theme/BlogListPage',
25
39
  blogArchiveComponent: '@theme/BlogArchivePage',
@@ -44,7 +58,76 @@ exports.DEFAULT_OPTIONS = {
44
58
  processBlogPosts: async () => undefined,
45
59
  onInlineTags: 'warn',
46
60
  tags: undefined,
61
+ authorsBasePath: 'authors',
62
+ onInlineAuthors: 'warn',
63
+ onUntruncatedBlogPosts: 'warn',
64
+ };
65
+ exports.XSLTBuiltInPaths = {
66
+ rss: path_1.default.resolve(__dirname, '..', 'assets', 'rss.xsl'),
67
+ atom: path_1.default.resolve(__dirname, '..', 'assets', 'atom.xsl'),
47
68
  };
69
+ function normalizeXsltOption(option, type) {
70
+ if (typeof option === 'string') {
71
+ return option;
72
+ }
73
+ if (option === true) {
74
+ return exports.XSLTBuiltInPaths[type];
75
+ }
76
+ return null;
77
+ }
78
+ function createXSLTFilePathSchema(type) {
79
+ return utils_validation_1.Joi.alternatives()
80
+ .try(utils_validation_1.Joi.string().required(), utils_validation_1.Joi.boolean()
81
+ .allow(null, () => undefined)
82
+ .custom((val) => normalizeXsltOption(val, type)))
83
+ .optional()
84
+ .default(null);
85
+ }
86
+ const FeedXSLTOptionsSchema = utils_validation_1.Joi.alternatives()
87
+ .try(utils_validation_1.Joi.object({
88
+ rss: createXSLTFilePathSchema('rss'),
89
+ atom: createXSLTFilePathSchema('atom'),
90
+ }).required(), utils_validation_1.Joi.boolean()
91
+ .allow(null, () => undefined)
92
+ .custom((val) => ({
93
+ rss: normalizeXsltOption(val, 'rss'),
94
+ atom: normalizeXsltOption(val, 'atom'),
95
+ })))
96
+ .optional()
97
+ .custom((val) => {
98
+ if (val === null) {
99
+ return {
100
+ rss: null,
101
+ atom: null,
102
+ };
103
+ }
104
+ return val;
105
+ })
106
+ .default(exports.DEFAULT_OPTIONS.feedOptions.xslt);
107
+ const FeedOptionsSchema = utils_validation_1.Joi.object({
108
+ type: utils_validation_1.Joi.alternatives()
109
+ .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'), {
110
+ then: utils_validation_1.Joi.custom((val) => val === 'all' ? ['rss', 'atom', 'json'] : [val]),
111
+ }))
112
+ .allow(null)
113
+ .default(exports.DEFAULT_OPTIONS.feedOptions.type),
114
+ xslt: FeedXSLTOptionsSchema,
115
+ title: utils_validation_1.Joi.string().allow(''),
116
+ description: utils_validation_1.Joi.string().allow(''),
117
+ // Only add default value when user actually wants a feed (type is not null)
118
+ copyright: utils_validation_1.Joi.when('type', {
119
+ is: utils_validation_1.Joi.any().valid(null),
120
+ then: utils_validation_1.Joi.string().optional(),
121
+ otherwise: utils_validation_1.Joi.string()
122
+ .allow('')
123
+ .default(exports.DEFAULT_OPTIONS.feedOptions.copyright),
124
+ }),
125
+ language: utils_validation_1.Joi.string(),
126
+ createFeedItems: utils_validation_1.Joi.function(),
127
+ limit: utils_validation_1.Joi.alternatives()
128
+ .try(utils_validation_1.Joi.number(), utils_validation_1.Joi.valid(null), utils_validation_1.Joi.valid(false))
129
+ .default(exports.DEFAULT_OPTIONS.feedOptions.limit),
130
+ }).default(exports.DEFAULT_OPTIONS.feedOptions);
48
131
  const PluginOptionSchema = utils_validation_1.Joi.object({
49
132
  path: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.path),
50
133
  archiveBasePath: utils_validation_1.Joi.string()
@@ -62,6 +145,8 @@ const PluginOptionSchema = utils_validation_1.Joi.object({
62
145
  blogPostComponent: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.blogPostComponent),
63
146
  blogTagsListComponent: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.blogTagsListComponent),
64
147
  blogTagsPostsComponent: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.blogTagsPostsComponent),
148
+ blogAuthorsPostsComponent: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.blogAuthorsPostsComponent),
149
+ blogAuthorsListComponent: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.blogAuthorsListComponent),
65
150
  blogArchiveComponent: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.blogArchiveComponent),
66
151
  blogTitle: utils_validation_1.Joi.string().allow('').default(exports.DEFAULT_OPTIONS.blogTitle),
67
152
  blogDescription: utils_validation_1.Joi.string()
@@ -74,35 +159,14 @@ const PluginOptionSchema = utils_validation_1.Joi.object({
74
159
  showReadingTime: utils_validation_1.Joi.bool().default(exports.DEFAULT_OPTIONS.showReadingTime),
75
160
  remarkPlugins: utils_validation_1.RemarkPluginsSchema.default(exports.DEFAULT_OPTIONS.remarkPlugins),
76
161
  rehypePlugins: utils_validation_1.RehypePluginsSchema.default(exports.DEFAULT_OPTIONS.rehypePlugins),
162
+ recmaPlugins: utils_validation_1.RecmaPluginsSchema.default(exports.DEFAULT_OPTIONS.recmaPlugins),
77
163
  admonitions: utils_validation_1.AdmonitionsSchema.default(exports.DEFAULT_OPTIONS.admonitions),
78
164
  editUrl: utils_validation_1.Joi.alternatives().try(utils_validation_1.URISchema, utils_validation_1.Joi.function()),
79
165
  editLocalizedFiles: utils_validation_1.Joi.boolean().default(exports.DEFAULT_OPTIONS.editLocalizedFiles),
80
166
  truncateMarker: utils_validation_1.Joi.object().default(exports.DEFAULT_OPTIONS.truncateMarker),
81
167
  beforeDefaultRemarkPlugins: utils_validation_1.RemarkPluginsSchema.default(exports.DEFAULT_OPTIONS.beforeDefaultRemarkPlugins),
82
168
  beforeDefaultRehypePlugins: utils_validation_1.RehypePluginsSchema.default(exports.DEFAULT_OPTIONS.beforeDefaultRehypePlugins),
83
- feedOptions: utils_validation_1.Joi.object({
84
- type: utils_validation_1.Joi.alternatives()
85
- .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'), {
86
- then: utils_validation_1.Joi.custom((val) => val === 'all' ? ['rss', 'atom', 'json'] : [val]),
87
- }))
88
- .allow(null)
89
- .default(exports.DEFAULT_OPTIONS.feedOptions.type),
90
- title: utils_validation_1.Joi.string().allow(''),
91
- description: utils_validation_1.Joi.string().allow(''),
92
- // Only add default value when user actually wants a feed (type is not null)
93
- copyright: utils_validation_1.Joi.when('type', {
94
- is: utils_validation_1.Joi.any().valid(null),
95
- then: utils_validation_1.Joi.string().optional(),
96
- otherwise: utils_validation_1.Joi.string()
97
- .allow('')
98
- .default(exports.DEFAULT_OPTIONS.feedOptions.copyright),
99
- }),
100
- language: utils_validation_1.Joi.string(),
101
- createFeedItems: utils_validation_1.Joi.function(),
102
- limit: utils_validation_1.Joi.alternatives()
103
- .try(utils_validation_1.Joi.number(), utils_validation_1.Joi.valid(null), utils_validation_1.Joi.valid(false))
104
- .default(exports.DEFAULT_OPTIONS.feedOptions.limit),
105
- }).default(exports.DEFAULT_OPTIONS.feedOptions),
169
+ feedOptions: FeedOptionsSchema,
106
170
  authorsMapPath: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.authorsMapPath),
107
171
  readingTime: utils_validation_1.Joi.function().default(() => exports.DEFAULT_OPTIONS.readingTime),
108
172
  sortPosts: utils_validation_1.Joi.string()
@@ -120,9 +184,17 @@ const PluginOptionSchema = utils_validation_1.Joi.object({
120
184
  .disallow('')
121
185
  .allow(null, false)
122
186
  .default(() => exports.DEFAULT_OPTIONS.tags),
187
+ authorsBasePath: utils_validation_1.Joi.string()
188
+ .default(exports.DEFAULT_OPTIONS.authorsBasePath)
189
+ .disallow(''),
190
+ onInlineAuthors: utils_validation_1.Joi.string()
191
+ .equal('ignore', 'log', 'warn', 'throw')
192
+ .default(exports.DEFAULT_OPTIONS.onInlineAuthors),
193
+ onUntruncatedBlogPosts: utils_validation_1.Joi.string()
194
+ .equal('ignore', 'log', 'warn', 'throw')
195
+ .default(exports.DEFAULT_OPTIONS.onUntruncatedBlogPosts),
123
196
  }).default(exports.DEFAULT_OPTIONS);
124
197
  function validateOptions({ validate, options, }) {
125
198
  const validatedOptions = validate(PluginOptionSchema, options);
126
199
  return validatedOptions;
127
200
  }
128
- exports.validateOptions = validateOptions;
package/lib/props.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- /// <reference path="../src/plugin-content-blog.d.ts" />
2
1
  /**
3
2
  * Copyright (c) Facebook, Inc. and its affiliates.
4
3
  *
@@ -6,7 +5,7 @@
6
5
  * LICENSE file in the root directory of this source tree.
7
6
  */
8
7
  import type { TagsListItem, TagModule } from '@docusaurus/utils';
9
- import type { BlogTag, BlogTags } from '@docusaurus/plugin-content-blog';
8
+ import type { AuthorItemProp, AuthorWithKey, BlogPost, BlogSidebar, BlogTag, BlogTags } from '@docusaurus/plugin-content-blog';
10
9
  export declare function toTagsProp({ blogTags }: {
11
10
  blogTags: BlogTags;
12
11
  }): TagsListItem[];
@@ -14,3 +13,11 @@ export declare function toTagProp({ blogTagsListPath, tag, }: {
14
13
  blogTagsListPath: string;
15
14
  tag: BlogTag;
16
15
  }): TagModule;
16
+ export declare function toAuthorItemProp({ author, count, }: {
17
+ author: AuthorWithKey;
18
+ count: number;
19
+ }): AuthorItemProp;
20
+ export declare function toBlogSidebarProp({ blogSidebarTitle, blogPosts, }: {
21
+ blogSidebarTitle: string;
22
+ blogPosts: BlogPost[];
23
+ }): BlogSidebar;
package/lib/props.js CHANGED
@@ -1,6 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.toTagProp = exports.toTagsProp = void 0;
3
+ exports.toTagsProp = toTagsProp;
4
+ exports.toTagProp = toTagProp;
5
+ exports.toAuthorItemProp = toAuthorItemProp;
6
+ exports.toBlogSidebarProp = toBlogSidebarProp;
4
7
  function toTagsProp({ blogTags }) {
5
8
  return Object.values(blogTags)
6
9
  .filter((tag) => !tag.unlisted)
@@ -11,7 +14,6 @@ function toTagsProp({ blogTags }) {
11
14
  count: tag.items.length,
12
15
  }));
13
16
  }
14
- exports.toTagsProp = toTagsProp;
15
17
  function toTagProp({ blogTagsListPath, tag, }) {
16
18
  return {
17
19
  label: tag.label,
@@ -22,4 +24,20 @@ function toTagProp({ blogTagsListPath, tag, }) {
22
24
  unlisted: tag.unlisted,
23
25
  };
24
26
  }
25
- exports.toTagProp = toTagProp;
27
+ function toAuthorItemProp({ author, count, }) {
28
+ return {
29
+ ...author,
30
+ count,
31
+ };
32
+ }
33
+ function toBlogSidebarProp({ blogSidebarTitle, blogPosts, }) {
34
+ return {
35
+ title: blogSidebarTitle,
36
+ items: blogPosts.map((blogPost) => ({
37
+ title: blogPost.metadata.title,
38
+ permalink: blogPost.metadata.permalink,
39
+ unlisted: blogPost.metadata.unlisted,
40
+ date: blogPost.metadata.date,
41
+ })),
42
+ };
43
+ }
@@ -6,6 +6,7 @@
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 = plugin;
9
10
  const utils_1 = require("@docusaurus/utils");
10
11
  /**
11
12
  * In the blog list view, each post will be compiled separately. However, they
@@ -25,4 +26,3 @@ function plugin() {
25
26
  });
26
27
  };
27
28
  }
28
- exports.default = plugin;
package/lib/routes.d.ts CHANGED
@@ -4,7 +4,6 @@
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
- /// <reference path="../src/plugin-content-blog.d.ts" />
8
7
  import type { PluginContentLoadedActions, RouteConfig } from '@docusaurus/types';
9
8
  import type { BlogContent, PluginOptions } from '@docusaurus/plugin-content-blog';
10
9
  type CreateAllRoutesParam = {