@docusaurus/plugin-content-blog 3.3.2 → 3.5.0

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 (62) 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 +7 -12
  14. package/lib/blogUtils.js +44 -34
  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 +8 -3
  26. package/lib/feed.js +111 -20
  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 +132 -105
  31. package/lib/markdownLoader.js +3 -7
  32. package/lib/options.d.ts +4 -1
  33. package/lib/options.js +107 -26
  34. package/lib/props.d.ts +9 -2
  35. package/lib/props.js +23 -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/lib/types.d.ts +1 -8
  42. package/package.json +13 -10
  43. package/src/authors.ts +56 -93
  44. package/src/authorsMap.ts +171 -0
  45. package/src/authorsProblems.ts +72 -0
  46. package/src/authorsSocials.ts +64 -0
  47. package/src/blogUtils.ts +51 -46
  48. package/src/client/contexts.tsx +95 -0
  49. package/src/client/index.tsx +24 -0
  50. package/src/client/sidebarUtils.test.ts +52 -0
  51. package/src/client/sidebarUtils.tsx +85 -0
  52. package/src/client/structuredDataUtils.ts +178 -0
  53. package/src/feed.ts +197 -18
  54. package/src/frontMatter.ts +2 -0
  55. package/src/index.ts +182 -137
  56. package/src/markdownLoader.ts +3 -7
  57. package/src/options.ts +132 -32
  58. package/src/plugin-content-blog.d.ts +252 -113
  59. package/src/props.ts +41 -1
  60. package/src/routes.ts +102 -12
  61. package/src/types.ts +1 -6
  62. package/src/client/index.ts +0 -20
package/lib/index.js CHANGED
@@ -7,28 +7,58 @@
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"));
13
14
  const utils_1 = require("@docusaurus/utils");
15
+ const utils_validation_1 = require("@docusaurus/utils-validation");
14
16
  const blogUtils_1 = require("./blogUtils");
15
17
  const footnoteIDFixer_1 = tslib_1.__importDefault(require("./remark/footnoteIDFixer"));
16
18
  const translations_1 = require("./translations");
17
19
  const feed_1 = require("./feed");
18
20
  const routes_1 = require("./routes");
21
+ const authorsMap_1 = require("./authorsMap");
22
+ const PluginName = 'docusaurus-plugin-content-blog';
23
+ // TODO this is bad, we should have a better way to do this (new lifecycle?)
24
+ // The source to permalink is currently a mutable map passed to the mdx loader
25
+ // for link resolution
26
+ // see https://github.com/facebook/docusaurus/pull/10185
27
+ function createSourceToPermalinkHelper() {
28
+ const sourceToPermalink = new Map();
29
+ function computeSourceToPermalink(content) {
30
+ return new Map(content.blogPosts.map(({ metadata: { source, permalink } }) => [
31
+ source,
32
+ permalink,
33
+ ]));
34
+ }
35
+ // Mutable map update :/
36
+ function update(content) {
37
+ sourceToPermalink.clear();
38
+ computeSourceToPermalink(content).forEach((value, key) => {
39
+ sourceToPermalink.set(key, value);
40
+ });
41
+ }
42
+ return { get: () => sourceToPermalink, update };
43
+ }
19
44
  async function pluginContentBlog(context, options) {
20
45
  const { siteDir, siteConfig, generatedFilesDir, localizationDir, i18n: { currentLocale }, } = context;
46
+ const router = siteConfig.future.experimental_router;
47
+ const isBlogFeedDisabledBecauseOfHashRouter = router === 'hash' && !!options.feedOptions.type;
48
+ if (isBlogFeedDisabledBecauseOfHashRouter) {
49
+ logger_1.default.warn(`${PluginName} feed feature does not support the Hash Router. Feeds won't be generated.`);
50
+ }
21
51
  const { onBrokenMarkdownLinks, baseUrl } = siteConfig;
22
52
  const contentPaths = {
23
53
  contentPath: path_1.default.resolve(siteDir, options.path),
24
54
  contentPathLocalized: (0, utils_1.getPluginI18nPath)({
25
55
  localizationDir,
26
- pluginName: 'docusaurus-plugin-content-blog',
56
+ pluginName: PluginName,
27
57
  pluginId: options.id,
28
58
  }),
29
59
  };
30
60
  const pluginId = options.id ?? utils_1.DEFAULT_PLUGIN_ID;
31
- const pluginDataDirRoot = path_1.default.join(generatedFilesDir, 'docusaurus-plugin-content-blog');
61
+ const pluginDataDirRoot = path_1.default.join(generatedFilesDir, PluginName);
32
62
  const dataDir = path_1.default.join(pluginDataDirRoot, pluginId);
33
63
  // TODO Docusaurus v4 breaking change
34
64
  // module aliasing should be automatic
@@ -38,26 +68,49 @@ async function pluginContentBlog(context, options) {
38
68
  filePath: options.authorsMapPath,
39
69
  contentPaths,
40
70
  });
71
+ const sourceToPermalinkHelper = createSourceToPermalinkHelper();
41
72
  return {
42
- name: 'docusaurus-plugin-content-blog',
73
+ name: PluginName,
43
74
  getPathsToWatch() {
44
75
  const { include } = options;
45
76
  const contentMarkdownGlobs = (0, utils_1.getContentPathList)(contentPaths).flatMap((contentPath) => include.map((pattern) => `${contentPath}/${pattern}`));
46
- return [authorsMapFilePath, ...contentMarkdownGlobs].filter(Boolean);
77
+ const tagsFilePaths = (0, utils_validation_1.getTagsFilePathsToWatch)({
78
+ contentPaths,
79
+ tags: options.tags,
80
+ });
81
+ return [
82
+ authorsMapFilePath,
83
+ ...tagsFilePaths,
84
+ ...contentMarkdownGlobs,
85
+ ].filter(Boolean);
47
86
  },
48
87
  getTranslationFiles() {
49
88
  return (0, translations_1.getTranslationFiles)(options);
50
89
  },
51
90
  // Fetches blog contents and returns metadata for the necessary routes.
52
91
  async loadContent() {
53
- const { postsPerPage: postsPerPageOption, routeBasePath, tagsBasePath, blogDescription, blogTitle, blogSidebarTitle, pageBasePath, } = options;
92
+ const { postsPerPage: postsPerPageOption, routeBasePath, tagsBasePath, blogDescription, blogTitle, blogSidebarTitle, pageBasePath, authorsBasePath, authorsMapPath, } = options;
54
93
  const baseBlogUrl = (0, utils_1.normalizeUrl)([baseUrl, routeBasePath]);
55
94
  const blogTagsListPath = (0, utils_1.normalizeUrl)([baseBlogUrl, tagsBasePath]);
56
- 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);
57
106
  blogPosts = await (0, blogUtils_1.applyProcessBlogPosts)({
58
107
  blogPosts,
59
108
  processBlogPosts: options.processBlogPosts,
60
109
  });
110
+ (0, blogUtils_1.reportUntruncatedBlogPosts)({
111
+ blogPosts,
112
+ onUntruncatedBlogPosts: options.onUntruncatedBlogPosts,
113
+ });
61
114
  const listedBlogPosts = blogPosts.filter(blogUtils_1.shouldBeListed);
62
115
  if (!blogPosts.length) {
63
116
  return {
@@ -66,6 +119,7 @@ async function pluginContentBlog(context, options) {
66
119
  blogListPaginated: [],
67
120
  blogTags: {},
68
121
  blogTagsListPath,
122
+ authorsMap,
69
123
  };
70
124
  }
71
125
  // Collocate next and prev metadata.
@@ -108,9 +162,11 @@ async function pluginContentBlog(context, options) {
108
162
  blogListPaginated,
109
163
  blogTags,
110
164
  blogTagsListPath,
165
+ authorsMap,
111
166
  };
112
167
  },
113
168
  async contentLoaded({ content, actions }) {
169
+ sourceToPermalinkHelper.update(content);
114
170
  await (0, routes_1.createAllRoutes)({
115
171
  baseUrl,
116
172
  content,
@@ -122,21 +178,67 @@ async function pluginContentBlog(context, options) {
122
178
  translateContent({ content, translationFiles }) {
123
179
  return (0, translations_1.translateContent)(content, translationFiles);
124
180
  },
125
- configureWebpack(_config, isServer, utils, content) {
126
- const { admonitions, rehypePlugins, remarkPlugins, truncateMarker, beforeDefaultRemarkPlugins, beforeDefaultRehypePlugins, } = options;
127
- const markdownLoaderOptions = {
128
- siteDir,
129
- contentPaths,
130
- truncateMarker,
131
- sourceToPermalink: (0, blogUtils_1.getSourceToPermalink)(content.blogPosts),
132
- onBrokenMarkdownLink: (brokenMarkdownLink) => {
133
- if (onBrokenMarkdownLinks === 'ignore') {
134
- return;
135
- }
136
- logger_1.default.report(onBrokenMarkdownLinks) `Blog markdown link couldn't be resolved: (url=${brokenMarkdownLink.link}) in path=${brokenMarkdownLink.filePath}`;
137
- },
138
- };
181
+ configureWebpack() {
182
+ const { admonitions, rehypePlugins, remarkPlugins, recmaPlugins, truncateMarker, beforeDefaultRemarkPlugins, beforeDefaultRehypePlugins, } = options;
139
183
  const contentDirs = (0, utils_1.getContentPathList)(contentPaths);
184
+ function createMDXLoader() {
185
+ const loaderOptions = {
186
+ admonitions,
187
+ remarkPlugins,
188
+ rehypePlugins,
189
+ recmaPlugins,
190
+ beforeDefaultRemarkPlugins: [
191
+ footnoteIDFixer_1.default,
192
+ ...beforeDefaultRemarkPlugins,
193
+ ],
194
+ beforeDefaultRehypePlugins,
195
+ staticDirs: siteConfig.staticDirectories.map((dir) => path_1.default.resolve(siteDir, dir)),
196
+ siteDir,
197
+ isMDXPartial: (0, utils_1.createAbsoluteFilePathMatcher)(options.exclude, contentDirs),
198
+ metadataPath: (mdxPath) => {
199
+ // Note that metadataPath must be the same/in-sync as
200
+ // the path from createData for each MDX.
201
+ const aliasedPath = (0, utils_1.aliasedSitePath)(mdxPath, siteDir);
202
+ return path_1.default.join(dataDir, `${(0, utils_1.docuHash)(aliasedPath)}.json`);
203
+ },
204
+ // For blog posts a title in markdown is always removed
205
+ // Blog posts title are rendered separately
206
+ removeContentTitle: true,
207
+ // Assets allow to convert some relative images paths to
208
+ // require() calls
209
+ // @ts-expect-error: TODO fix typing issue
210
+ createAssets: ({ frontMatter, metadata, }) => ({
211
+ image: frontMatter.image,
212
+ authorsImageUrls: metadata.authors.map((author) => author.imageURL),
213
+ }),
214
+ markdownConfig: siteConfig.markdown,
215
+ resolveMarkdownLink: ({ linkPathname, sourceFilePath }) => {
216
+ const permalink = (0, utils_1.resolveMarkdownLinkPathname)(linkPathname, {
217
+ sourceFilePath,
218
+ sourceToPermalink: sourceToPermalinkHelper.get(),
219
+ siteDir,
220
+ contentPaths,
221
+ });
222
+ if (permalink === null) {
223
+ logger_1.default.report(onBrokenMarkdownLinks) `Blog markdown link couldn't be resolved: (url=${linkPathname}) in source file path=${sourceFilePath}`;
224
+ }
225
+ return permalink;
226
+ },
227
+ };
228
+ return {
229
+ loader: require.resolve('@docusaurus/mdx-loader'),
230
+ options: loaderOptions,
231
+ };
232
+ }
233
+ function createBlogMarkdownLoader() {
234
+ const loaderOptions = {
235
+ truncateMarker,
236
+ };
237
+ return {
238
+ loader: path_1.default.resolve(__dirname, './markdownLoader.js'),
239
+ options: loaderOptions,
240
+ };
241
+ }
140
242
  return {
141
243
  resolve: {
142
244
  alias: {
@@ -150,111 +252,36 @@ async function pluginContentBlog(context, options) {
150
252
  include: contentDirs
151
253
  // Trailing slash is important, see https://github.com/facebook/docusaurus/pull/3970
152
254
  .map(utils_1.addTrailingPathSeparator),
153
- use: [
154
- {
155
- loader: require.resolve('@docusaurus/mdx-loader'),
156
- options: {
157
- admonitions,
158
- remarkPlugins,
159
- rehypePlugins,
160
- beforeDefaultRemarkPlugins: [
161
- footnoteIDFixer_1.default,
162
- ...beforeDefaultRemarkPlugins,
163
- ],
164
- beforeDefaultRehypePlugins,
165
- staticDirs: siteConfig.staticDirectories.map((dir) => path_1.default.resolve(siteDir, dir)),
166
- siteDir,
167
- isMDXPartial: (0, utils_1.createAbsoluteFilePathMatcher)(options.exclude, contentDirs),
168
- metadataPath: (mdxPath) => {
169
- // Note that metadataPath must be the same/in-sync as
170
- // the path from createData for each MDX.
171
- const aliasedPath = (0, utils_1.aliasedSitePath)(mdxPath, siteDir);
172
- return path_1.default.join(dataDir, `${(0, utils_1.docuHash)(aliasedPath)}.json`);
173
- },
174
- // For blog posts a title in markdown is always removed
175
- // Blog posts title are rendered separately
176
- removeContentTitle: true,
177
- // Assets allow to convert some relative images paths to
178
- // require() calls
179
- createAssets: ({ frontMatter, metadata, }) => ({
180
- image: frontMatter.image,
181
- authorsImageUrls: metadata.authors.map((author) => author.imageURL),
182
- }),
183
- markdownConfig: siteConfig.markdown,
184
- },
185
- },
186
- {
187
- loader: path_1.default.resolve(__dirname, './markdownLoader.js'),
188
- options: markdownLoaderOptions,
189
- },
190
- ].filter(Boolean),
255
+ use: [createMDXLoader(), createBlogMarkdownLoader()],
191
256
  },
192
257
  ],
193
258
  },
194
259
  };
195
260
  },
196
261
  async postBuild({ outDir, content }) {
197
- if (!options.feedOptions.type) {
198
- return;
199
- }
200
- const { blogPosts } = content;
201
- if (!blogPosts.length) {
262
+ if (!content.blogPosts.length ||
263
+ !options.feedOptions.type ||
264
+ isBlogFeedDisabledBecauseOfHashRouter) {
202
265
  return;
203
266
  }
204
267
  await (0, feed_1.createBlogFeedFiles)({
205
- blogPosts,
268
+ blogPosts: content.blogPosts,
206
269
  options,
207
270
  outDir,
208
271
  siteConfig,
209
272
  locale: currentLocale,
273
+ contentPaths,
210
274
  });
211
275
  },
212
276
  injectHtmlTags({ content }) {
213
- if (!content.blogPosts.length || !options.feedOptions.type) {
277
+ if (!content.blogPosts.length ||
278
+ !options.feedOptions.type ||
279
+ isBlogFeedDisabledBecauseOfHashRouter) {
214
280
  return {};
215
281
  }
216
- const feedTypes = options.feedOptions.type;
217
- const feedTitle = options.feedOptions.title ?? context.siteConfig.title;
218
- const feedsConfig = {
219
- rss: {
220
- type: 'application/rss+xml',
221
- path: 'rss.xml',
222
- title: `${feedTitle} RSS Feed`,
223
- },
224
- atom: {
225
- type: 'application/atom+xml',
226
- path: 'atom.xml',
227
- title: `${feedTitle} Atom Feed`,
228
- },
229
- json: {
230
- type: 'application/json',
231
- path: 'feed.json',
232
- title: `${feedTitle} JSON Feed`,
233
- },
234
- };
235
- const headTags = [];
236
- feedTypes.forEach((feedType) => {
237
- const { type, path: feedConfigPath, title: feedConfigTitle, } = feedsConfig[feedType];
238
- headTags.push({
239
- tagName: 'link',
240
- attributes: {
241
- rel: 'alternate',
242
- type,
243
- href: (0, utils_1.normalizeUrl)([
244
- baseUrl,
245
- options.routeBasePath,
246
- feedConfigPath,
247
- ]),
248
- title: feedConfigTitle,
249
- },
250
- });
251
- });
252
- return {
253
- headTags,
254
- };
282
+ return { headTags: (0, feed_1.createFeedHtmlHeadTags)({ context, options }) };
255
283
  },
256
284
  };
257
285
  }
258
- exports.default = pluginContentBlog;
259
286
  var options_1 = require("./options");
260
287
  Object.defineProperty(exports, "validateOptions", { enumerable: true, get: function () { return options_1.validateOptions; } });
@@ -6,25 +6,21 @@
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
- const filePath = this.resourcePath;
12
12
  const fileString = source;
13
13
  const callback = this.async();
14
14
  const markdownLoaderOptions = this.getOptions();
15
15
  // Linkify blog posts
16
- let finalContent = (0, blogUtils_1.linkify)({
17
- fileString,
18
- filePath,
19
- ...markdownLoaderOptions,
20
- });
16
+ let finalContent = fileString;
21
17
  // Truncate content if requested (e.g: file.md?truncated=true).
22
18
  const truncated = this.resourceQuery
23
19
  ? !!new URLSearchParams(this.resourceQuery.slice(1)).get('truncated')
24
20
  : undefined;
21
+ // TODO truncate with the AST instead of the string ?
25
22
  if (truncated) {
26
23
  finalContent = (0, blogUtils_1.truncate)(finalContent, markdownLoaderOptions.truncateMarker);
27
24
  }
28
25
  return callback(null, finalContent);
29
26
  }
30
- 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',
@@ -42,7 +56,78 @@ exports.DEFAULT_OPTIONS = {
42
56
  showLastUpdateTime: false,
43
57
  showLastUpdateAuthor: false,
44
58
  processBlogPosts: async () => undefined,
59
+ onInlineTags: 'warn',
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'),
45
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);
46
131
  const PluginOptionSchema = utils_validation_1.Joi.object({
47
132
  path: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.path),
48
133
  archiveBasePath: utils_validation_1.Joi.string()
@@ -60,6 +145,8 @@ const PluginOptionSchema = utils_validation_1.Joi.object({
60
145
  blogPostComponent: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.blogPostComponent),
61
146
  blogTagsListComponent: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.blogTagsListComponent),
62
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),
63
150
  blogArchiveComponent: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.blogArchiveComponent),
64
151
  blogTitle: utils_validation_1.Joi.string().allow('').default(exports.DEFAULT_OPTIONS.blogTitle),
65
152
  blogDescription: utils_validation_1.Joi.string()
@@ -72,35 +159,14 @@ const PluginOptionSchema = utils_validation_1.Joi.object({
72
159
  showReadingTime: utils_validation_1.Joi.bool().default(exports.DEFAULT_OPTIONS.showReadingTime),
73
160
  remarkPlugins: utils_validation_1.RemarkPluginsSchema.default(exports.DEFAULT_OPTIONS.remarkPlugins),
74
161
  rehypePlugins: utils_validation_1.RehypePluginsSchema.default(exports.DEFAULT_OPTIONS.rehypePlugins),
162
+ recmaPlugins: utils_validation_1.RecmaPluginsSchema.default(exports.DEFAULT_OPTIONS.recmaPlugins),
75
163
  admonitions: utils_validation_1.AdmonitionsSchema.default(exports.DEFAULT_OPTIONS.admonitions),
76
164
  editUrl: utils_validation_1.Joi.alternatives().try(utils_validation_1.URISchema, utils_validation_1.Joi.function()),
77
165
  editLocalizedFiles: utils_validation_1.Joi.boolean().default(exports.DEFAULT_OPTIONS.editLocalizedFiles),
78
166
  truncateMarker: utils_validation_1.Joi.object().default(exports.DEFAULT_OPTIONS.truncateMarker),
79
167
  beforeDefaultRemarkPlugins: utils_validation_1.RemarkPluginsSchema.default(exports.DEFAULT_OPTIONS.beforeDefaultRemarkPlugins),
80
168
  beforeDefaultRehypePlugins: utils_validation_1.RehypePluginsSchema.default(exports.DEFAULT_OPTIONS.beforeDefaultRehypePlugins),
81
- feedOptions: utils_validation_1.Joi.object({
82
- type: utils_validation_1.Joi.alternatives()
83
- .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'), {
84
- then: utils_validation_1.Joi.custom((val) => val === 'all' ? ['rss', 'atom', 'json'] : [val]),
85
- }))
86
- .allow(null)
87
- .default(exports.DEFAULT_OPTIONS.feedOptions.type),
88
- title: utils_validation_1.Joi.string().allow(''),
89
- description: utils_validation_1.Joi.string().allow(''),
90
- // Only add default value when user actually wants a feed (type is not null)
91
- copyright: utils_validation_1.Joi.when('type', {
92
- is: utils_validation_1.Joi.any().valid(null),
93
- then: utils_validation_1.Joi.string().optional(),
94
- otherwise: utils_validation_1.Joi.string()
95
- .allow('')
96
- .default(exports.DEFAULT_OPTIONS.feedOptions.copyright),
97
- }),
98
- language: utils_validation_1.Joi.string(),
99
- createFeedItems: utils_validation_1.Joi.function(),
100
- limit: utils_validation_1.Joi.alternatives()
101
- .try(utils_validation_1.Joi.number(), utils_validation_1.Joi.valid(null), utils_validation_1.Joi.valid(false))
102
- .default(exports.DEFAULT_OPTIONS.feedOptions.limit),
103
- }).default(exports.DEFAULT_OPTIONS.feedOptions),
169
+ feedOptions: FeedOptionsSchema,
104
170
  authorsMapPath: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.authorsMapPath),
105
171
  readingTime: utils_validation_1.Joi.function().default(() => exports.DEFAULT_OPTIONS.readingTime),
106
172
  sortPosts: utils_validation_1.Joi.string()
@@ -111,9 +177,24 @@ const PluginOptionSchema = utils_validation_1.Joi.object({
111
177
  processBlogPosts: utils_validation_1.Joi.function()
112
178
  .optional()
113
179
  .default(() => exports.DEFAULT_OPTIONS.processBlogPosts),
180
+ onInlineTags: utils_validation_1.Joi.string()
181
+ .equal('ignore', 'log', 'warn', 'throw')
182
+ .default(exports.DEFAULT_OPTIONS.onInlineTags),
183
+ tags: utils_validation_1.Joi.string()
184
+ .disallow('')
185
+ .allow(null, false)
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),
114
196
  }).default(exports.DEFAULT_OPTIONS);
115
197
  function validateOptions({ validate, options, }) {
116
198
  const validatedOptions = validate(PluginOptionSchema, options);
117
199
  return validatedOptions;
118
200
  }
119
- 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,23 +1,43 @@
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)
7
10
  .map((tag) => ({
8
11
  label: tag.label,
9
12
  permalink: tag.permalink,
13
+ description: tag.description,
10
14
  count: tag.items.length,
11
15
  }));
12
16
  }
13
- exports.toTagsProp = toTagsProp;
14
17
  function toTagProp({ blogTagsListPath, tag, }) {
15
18
  return {
16
19
  label: tag.label,
17
20
  permalink: tag.permalink,
21
+ description: tag.description,
18
22
  allTagsPath: blogTagsListPath,
19
23
  count: tag.items.length,
20
24
  unlisted: tag.unlisted,
21
25
  };
22
26
  }
23
- 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 = {