@docusaurus/plugin-content-blog 2.0.0-beta.16 → 2.0.0-beta.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/authors.d.ts CHANGED
@@ -6,7 +6,9 @@
6
6
  */
7
7
  import type { BlogContentPaths } from './types';
8
8
  import type { Author, BlogPostFrontMatter } from '@docusaurus/plugin-content-blog';
9
- export declare type AuthorsMap = Record<string, Author>;
9
+ export declare type AuthorsMap = {
10
+ [authorKey: string]: Author;
11
+ };
10
12
  export declare function validateAuthorsMap(content: unknown): AuthorsMap;
11
13
  export declare function getAuthorsMap(params: {
12
14
  authorsMapPath: string;
package/lib/authors.js CHANGED
@@ -9,16 +9,25 @@ Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.getBlogPostAuthors = exports.getAuthorsMap = exports.validateAuthorsMap = void 0;
10
10
  const utils_1 = require("@docusaurus/utils");
11
11
  const utils_validation_1 = require("@docusaurus/utils-validation");
12
- const AuthorsMapSchema = utils_validation_1.Joi.object().pattern(utils_validation_1.Joi.string(), utils_validation_1.Joi.object({
12
+ const AuthorsMapSchema = utils_validation_1.Joi.object()
13
+ .pattern(utils_validation_1.Joi.string(), utils_validation_1.Joi.object({
13
14
  name: utils_validation_1.Joi.string(),
14
15
  url: utils_validation_1.URISchema,
15
16
  imageURL: utils_validation_1.URISchema,
16
17
  title: utils_validation_1.Joi.string(),
18
+ email: utils_validation_1.Joi.string(),
17
19
  })
18
20
  .rename('image_url', 'imageURL')
19
21
  .or('name', 'imageURL')
20
22
  .unknown()
21
- .required());
23
+ .required()
24
+ .messages({
25
+ 'object.base': '{#label} should be an author object containing properties like name, title, and imageURL.',
26
+ 'any.required': '{#label} cannot be undefined. It should be an author object containing properties like name, title, and imageURL.',
27
+ }))
28
+ .messages({
29
+ 'object.base': "The authors map file should contain an object where each entry contains an author key and the corresponding author's data.",
30
+ });
22
31
  function validateAuthorsMap(content) {
23
32
  return utils_validation_1.Joi.attempt(content, AuthorsMapSchema);
24
33
  }
@@ -34,11 +43,10 @@ exports.getAuthorsMap = getAuthorsMap;
34
43
  // Legacy v1/early-v2 front matter fields
35
44
  // We may want to deprecate those in favor of using only frontMatter.authors
36
45
  function getFrontMatterAuthorLegacy(frontMatter) {
37
- var _a, _b, _c;
38
46
  const name = frontMatter.author;
39
- const title = (_a = frontMatter.author_title) !== null && _a !== void 0 ? _a : frontMatter.authorTitle;
40
- const url = (_b = frontMatter.author_url) !== null && _b !== void 0 ? _b : frontMatter.authorURL;
41
- const imageURL = (_c = frontMatter.author_image_url) !== null && _c !== void 0 ? _c : frontMatter.authorImageURL;
47
+ const title = frontMatter.author_title ?? frontMatter.authorTitle;
48
+ const url = frontMatter.author_url ?? frontMatter.authorURL;
49
+ const imageURL = frontMatter.author_image_url ?? frontMatter.authorImageURL;
42
50
  if (name || title || url || imageURL) {
43
51
  return {
44
52
  name,
@@ -4,11 +4,13 @@
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 { BlogPost, BlogContentPaths, BlogMarkdownLoaderOptions, BlogTags, BlogPaginated } from './types';
7
+ import type { BlogContentPaths, BlogMarkdownLoaderOptions } from './types';
8
8
  import type { LoadContext } from '@docusaurus/types';
9
- import type { PluginOptions } from '@docusaurus/plugin-content-blog';
9
+ import type { PluginOptions, BlogPost, BlogTags, BlogPaginated } from '@docusaurus/plugin-content-blog';
10
10
  export declare function truncate(fileString: string, truncateMarker: RegExp): string;
11
- export declare function getSourceToPermalink(blogPosts: BlogPost[]): Record<string, string>;
11
+ export declare function getSourceToPermalink(blogPosts: BlogPost[]): {
12
+ [aliasedPath: string]: string;
13
+ };
12
14
  export declare function paginateBlogPosts({ blogPosts, basePageUrl, blogTitle, blogDescription, postsPerPageOption, }: {
13
15
  blogPosts: BlogPost[];
14
16
  basePageUrl: string;
package/lib/blogUtils.js CHANGED
@@ -8,14 +8,14 @@
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.linkify = exports.generateBlogPosts = exports.parseBlogFileName = exports.getBlogTags = exports.paginateBlogPosts = exports.getSourceToPermalink = exports.truncate = void 0;
10
10
  const tslib_1 = require("tslib");
11
- const fs_extra_1 = (0, tslib_1.__importDefault)(require("fs-extra"));
12
- const path_1 = (0, tslib_1.__importDefault)(require("path"));
13
- const reading_time_1 = (0, tslib_1.__importDefault)(require("reading-time"));
14
- const lodash_1 = (0, tslib_1.__importDefault)(require("lodash"));
11
+ const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
12
+ const path_1 = tslib_1.__importDefault(require("path"));
13
+ const reading_time_1 = tslib_1.__importDefault(require("reading-time"));
14
+ const lodash_1 = tslib_1.__importDefault(require("lodash"));
15
15
  const utils_1 = require("@docusaurus/utils");
16
- const blogFrontMatter_1 = require("./blogFrontMatter");
16
+ const frontMatter_1 = require("./frontMatter");
17
17
  const authors_1 = require("./authors");
18
- const logger_1 = (0, tslib_1.__importDefault)(require("@docusaurus/logger"));
18
+ const logger_1 = tslib_1.__importDefault(require("@docusaurus/logger"));
19
19
  function truncate(fileString, truncateMarker) {
20
20
  return fileString.split(truncateMarker, 1).shift();
21
21
  }
@@ -30,7 +30,9 @@ function paginateBlogPosts({ blogPosts, basePageUrl, blogTitle, blogDescription,
30
30
  const numberOfPages = Math.ceil(totalCount / postsPerPage);
31
31
  const pages = [];
32
32
  function permalink(page) {
33
- return page > 0 ? `${basePageUrl}/page/${page + 1}` : basePageUrl;
33
+ return page > 0
34
+ ? (0, utils_1.normalizeUrl)([basePageUrl, `page/${page + 1}`])
35
+ : basePageUrl;
34
36
  }
35
37
  for (let page = 0; page < numberOfPages; page += 1) {
36
38
  pages.push({
@@ -43,8 +45,8 @@ function paginateBlogPosts({ blogPosts, basePageUrl, blogTitle, blogDescription,
43
45
  postsPerPage,
44
46
  totalPages: numberOfPages,
45
47
  totalCount,
46
- previousPage: page !== 0 ? permalink(page - 1) : null,
47
- nextPage: page < numberOfPages - 1 ? permalink(page + 1) : null,
48
+ previousPage: page !== 0 ? permalink(page - 1) : undefined,
49
+ nextPage: page < numberOfPages - 1 ? permalink(page + 1) : undefined,
48
50
  blogDescription,
49
51
  blogTitle,
50
52
  },
@@ -56,7 +58,7 @@ exports.paginateBlogPosts = paginateBlogPosts;
56
58
  function getBlogTags({ blogPosts, ...params }) {
57
59
  const groups = (0, utils_1.groupTaggedItems)(blogPosts, (blogPost) => blogPost.metadata.tags);
58
60
  return lodash_1.default.mapValues(groups, ({ tag, items: tagBlogPosts }) => ({
59
- name: tag.label,
61
+ label: tag.label,
60
62
  items: tagBlogPosts.map((item) => item.id),
61
63
  permalink: tag.permalink,
62
64
  pages: paginateBlogPosts({
@@ -76,20 +78,21 @@ function parseBlogFileName(blogSourceRelative) {
76
78
  const date = new Date(`${dateString}Z`);
77
79
  const slugDate = dateString.replace(/-/g, '/');
78
80
  const slug = `/${slugDate}/${folder}${text}`;
79
- return { date, text, slug };
81
+ return { date, text: text, slug };
80
82
  }
81
83
  const text = blogSourceRelative.replace(/(?:\/index)?\.mdx?$/, '');
82
84
  const slug = `/${text}`;
83
85
  return { date: undefined, text, slug };
84
86
  }
85
87
  exports.parseBlogFileName = parseBlogFileName;
86
- function formatBlogPostDate(locale, date) {
88
+ function formatBlogPostDate(locale, date, calendar) {
87
89
  try {
88
90
  return new Intl.DateTimeFormat(locale, {
89
91
  day: 'numeric',
90
92
  month: 'long',
91
93
  year: 'numeric',
92
94
  timeZone: 'UTC',
95
+ calendar,
93
96
  }).format(date);
94
97
  }
95
98
  catch (err) {
@@ -105,7 +108,7 @@ async function parseBlogPostMarkdownFile(blogSourceAbsolute) {
105
108
  });
106
109
  return {
107
110
  ...result,
108
- frontMatter: (0, blogFrontMatter_1.validateBlogPostFrontMatter)(result.frontMatter),
111
+ frontMatter: (0, frontMatter_1.validateBlogPostFrontMatter)(result.frontMatter),
109
112
  };
110
113
  }
111
114
  catch (err) {
@@ -115,7 +118,6 @@ async function parseBlogPostMarkdownFile(blogSourceAbsolute) {
115
118
  }
116
119
  const defaultReadingTime = ({ content, options }) => (0, reading_time_1.default)(content, options).minutes;
117
120
  async function processBlogSourceFile(blogSourceRelative, contentPaths, context, options, authorsMap) {
118
- var _a, _b, _c, _d;
119
121
  const { siteConfig: { baseUrl }, siteDir, i18n, } = context;
120
122
  const { routeBasePath, tagsBasePath: tagsRouteBasePath, truncateMarker, showReadingTime, editUrl, } = options;
121
123
  // Lookup in localized folder in priority
@@ -151,14 +153,14 @@ async function processBlogSourceFile(blogSourceRelative, contentPaths, context,
151
153
  return result.date;
152
154
  }
153
155
  catch (err) {
154
- logger_1.default.error(err);
156
+ logger_1.default.warn(err);
155
157
  return (await fs_extra_1.default.stat(blogSourceAbsolute)).birthtime;
156
158
  }
157
159
  }
158
160
  const date = await getDate();
159
- const formattedDate = formatBlogPostDate(i18n.currentLocale, date);
160
- const title = (_b = (_a = frontMatter.title) !== null && _a !== void 0 ? _a : contentTitle) !== null && _b !== void 0 ? _b : parsedBlogFileName.text;
161
- const description = (_d = (_c = frontMatter.description) !== null && _c !== void 0 ? _c : excerpt) !== null && _d !== void 0 ? _d : '';
161
+ const formattedDate = formatBlogPostDate(i18n.currentLocale, date, i18n.localeConfigs[i18n.currentLocale].calendar);
162
+ const title = frontMatter.title ?? contentTitle ?? parsedBlogFileName.text;
163
+ const description = frontMatter.description ?? excerpt ?? '';
162
164
  const slug = frontMatter.slug || parsedBlogFileName.slug;
163
165
  const permalink = (0, utils_1.normalizeUrl)([baseUrl, routeBasePath, slug]);
164
166
  function getBlogEditUrl() {
@@ -208,7 +210,7 @@ async function processBlogSourceFile(blogSourceRelative, contentPaths, context,
208
210
  defaultReadingTime,
209
211
  })
210
212
  : undefined,
211
- truncated: (truncateMarker === null || truncateMarker === void 0 ? void 0 : truncateMarker.test(content)) || false,
213
+ truncated: truncateMarker?.test(content) || false,
212
214
  authors,
213
215
  frontMatter,
214
216
  },
package/lib/feed.d.ts CHANGED
@@ -4,12 +4,12 @@
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 { BlogPost } from './types';
8
7
  import type { DocusaurusConfig } from '@docusaurus/types';
9
- import type { PluginOptions } from '@docusaurus/plugin-content-blog';
10
- export declare function createBlogFeedFiles({ blogPosts, options, siteConfig, outDir, }: {
8
+ import type { PluginOptions, BlogPost } from '@docusaurus/plugin-content-blog';
9
+ export declare function createBlogFeedFiles({ blogPosts, options, siteConfig, outDir, locale, }: {
11
10
  blogPosts: BlogPost[];
12
11
  options: PluginOptions;
13
12
  siteConfig: DocusaurusConfig;
14
13
  outDir: string;
14
+ locale: string;
15
15
  }): Promise<void>;
package/lib/feed.js CHANGED
@@ -10,37 +10,35 @@ exports.createBlogFeedFiles = void 0;
10
10
  const tslib_1 = require("tslib");
11
11
  const feed_1 = require("feed");
12
12
  const utils_1 = require("@docusaurus/utils");
13
- const cheerio_1 = (0, tslib_1.__importDefault)(require("cheerio"));
14
- const path_1 = (0, tslib_1.__importDefault)(require("path"));
15
- const fs_extra_1 = (0, tslib_1.__importDefault)(require("fs-extra"));
13
+ const cheerio_1 = require("cheerio");
14
+ const path_1 = tslib_1.__importDefault(require("path"));
15
+ const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
16
16
  const utils_common_1 = require("@docusaurus/utils-common");
17
- async function generateBlogFeed({ blogPosts, options, siteConfig, outDir, }) {
17
+ async function generateBlogFeed({ blogPosts, options, siteConfig, outDir, locale, }) {
18
18
  if (!blogPosts.length) {
19
19
  return null;
20
20
  }
21
21
  const { feedOptions, routeBasePath } = options;
22
22
  const { url: siteUrl, baseUrl, title, favicon } = siteConfig;
23
23
  const blogBaseUrl = (0, utils_1.normalizeUrl)([siteUrl, baseUrl, routeBasePath]);
24
- const updated = blogPosts[0] && blogPosts[0].metadata.date;
24
+ const updated = blogPosts[0]?.metadata.date;
25
25
  const feed = new feed_1.Feed({
26
26
  id: blogBaseUrl,
27
- title: feedOptions.title || `${title} Blog`,
27
+ title: feedOptions.title ?? `${title} Blog`,
28
28
  updated,
29
- language: feedOptions.language,
29
+ language: feedOptions.language ?? locale,
30
30
  link: blogBaseUrl,
31
- description: feedOptions.description || `${siteConfig.title} Blog`,
31
+ description: feedOptions.description ?? `${siteConfig.title} Blog`,
32
32
  favicon: favicon ? (0, utils_1.normalizeUrl)([siteUrl, baseUrl, favicon]) : undefined,
33
33
  copyright: feedOptions.copyright,
34
34
  });
35
35
  function toFeedAuthor(author) {
36
- // TODO ask author emails?
37
- // RSS feed requires email to render authors
38
- return { name: author.name, link: author.url };
36
+ return { name: author.name, link: author.url, email: author.email };
39
37
  }
40
- await (0, utils_1.mapAsyncSequential)(blogPosts, async (post) => {
38
+ await Promise.all(blogPosts.map(async (post) => {
41
39
  const { id, metadata: { title: metadataTitle, permalink, date, description, authors, tags, }, } = post;
42
40
  const content = await (0, utils_1.readOutputHTMLFile)(permalink.replace(siteConfig.baseUrl, ''), outDir, siteConfig.trailingSlash);
43
- const $ = cheerio_1.default.load(content);
41
+ const $ = (0, cheerio_1.load)(content);
44
42
  const feedItem = {
45
43
  title: metadataTitle,
46
44
  id,
@@ -57,8 +55,8 @@ async function generateBlogFeed({ blogPosts, options, siteConfig, outDir, }) {
57
55
  if (feedItemAuthors.length > 0) {
58
56
  feedItem.author = feedItemAuthors;
59
57
  }
60
- feed.addItem(feedItem);
61
- });
58
+ return feedItem;
59
+ })).then((items) => items.forEach(feed.addItem));
62
60
  return feed;
63
61
  }
64
62
  async function createBlogFeedFile({ feed, feedType, generatePath, }) {
@@ -75,18 +73,19 @@ async function createBlogFeedFile({ feed, feedType, generatePath, }) {
75
73
  }
76
74
  })();
77
75
  try {
78
- await fs_extra_1.default.outputFile((0, utils_1.posixPath)(path_1.default.join(generatePath, feedPath)), feedContent);
76
+ await fs_extra_1.default.outputFile(path_1.default.join(generatePath, feedPath), feedContent);
79
77
  }
80
78
  catch (err) {
81
79
  throw new Error(`Generating ${feedType} feed failed: ${err}.`);
82
80
  }
83
81
  }
84
- async function createBlogFeedFiles({ blogPosts, options, siteConfig, outDir, }) {
82
+ async function createBlogFeedFiles({ blogPosts, options, siteConfig, outDir, locale, }) {
85
83
  const feed = await generateBlogFeed({
86
84
  blogPosts,
87
85
  options,
88
86
  siteConfig,
89
87
  outDir,
88
+ locale,
90
89
  });
91
90
  const feedTypes = options.feedOptions.type;
92
91
  if (!feed || !feedTypes) {
@@ -5,4 +5,6 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  import type { BlogPostFrontMatter } from '@docusaurus/plugin-content-blog';
8
- export declare function validateBlogPostFrontMatter(frontMatter: Record<string, unknown>): BlogPostFrontMatter;
8
+ export declare function validateBlogPostFrontMatter(frontMatter: {
9
+ [key: string]: unknown;
10
+ }): BlogPostFrontMatter;
File without changes
package/lib/index.d.ts CHANGED
@@ -4,8 +4,7 @@
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 { BlogContent } from './types';
8
- import type { LoadContext, Plugin, OptionValidationContext, ValidationResult } from '@docusaurus/types';
9
- import type { PluginOptions } from '@docusaurus/plugin-content-blog';
7
+ import type { LoadContext, Plugin } from '@docusaurus/types';
8
+ import type { PluginOptions, BlogContent } from '@docusaurus/plugin-content-blog';
10
9
  export default function pluginContentBlog(context: LoadContext, options: PluginOptions): Promise<Plugin<BlogContent>>;
11
- export declare function validateOptions({ validate, options, }: OptionValidationContext<PluginOptions>): ValidationResult<PluginOptions>;
10
+ export { validateOptions } from './options';
package/lib/index.js CHANGED
@@ -8,15 +8,14 @@
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.validateOptions = void 0;
10
10
  const tslib_1 = require("tslib");
11
- const path_1 = (0, tslib_1.__importDefault)(require("path"));
12
- const remark_admonitions_1 = (0, tslib_1.__importDefault)(require("remark-admonitions"));
11
+ const path_1 = tslib_1.__importDefault(require("path"));
12
+ const remark_admonitions_1 = tslib_1.__importDefault(require("remark-admonitions"));
13
+ const footnoteIDFixer_1 = tslib_1.__importDefault(require("./remark/footnoteIDFixer"));
13
14
  const utils_1 = require("@docusaurus/utils");
14
15
  const translations_1 = require("./translations");
15
- const pluginOptionSchema_1 = require("./pluginOptionSchema");
16
16
  const blogUtils_1 = require("./blogUtils");
17
17
  const feed_1 = require("./feed");
18
18
  async function pluginContentBlog(context, options) {
19
- var _a;
20
19
  if (options.admonitions) {
21
20
  options.remarkPlugins = options.remarkPlugins.concat([
22
21
  [remark_admonitions_1.default, options.admonitions],
@@ -33,7 +32,7 @@ async function pluginContentBlog(context, options) {
33
32
  pluginId: options.id,
34
33
  }),
35
34
  };
36
- const pluginId = (_a = options.id) !== null && _a !== void 0 ? _a : utils_1.DEFAULT_PLUGIN_ID;
35
+ const pluginId = options.id ?? utils_1.DEFAULT_PLUGIN_ID;
37
36
  const pluginDataDirRoot = path_1.default.join(generatedFilesDir, 'docusaurus-plugin-content-blog');
38
37
  const dataDir = path_1.default.join(pluginDataDirRoot, pluginId);
39
38
  const aliasedSource = (source) => `~blog/${(0, utils_1.posixPath)(path_1.default.relative(pluginDataDirRoot, source))}`;
@@ -48,12 +47,14 @@ async function pluginContentBlog(context, options) {
48
47
  const contentMarkdownGlobs = (0, utils_1.getContentPathList)(contentPaths).flatMap((contentPath) => include.map((pattern) => `${contentPath}/${pattern}`));
49
48
  return [authorsMapFilePath, ...contentMarkdownGlobs].filter(Boolean);
50
49
  },
51
- async getTranslationFiles() {
50
+ getTranslationFiles() {
52
51
  return (0, translations_1.getTranslationFiles)(options);
53
52
  },
54
53
  // Fetches blog contents and returns metadata for the necessary routes.
55
54
  async loadContent() {
56
55
  const { postsPerPage: postsPerPageOption, routeBasePath, tagsBasePath, blogDescription, blogTitle, blogSidebarTitle, } = options;
56
+ const baseBlogUrl = (0, utils_1.normalizeUrl)([baseUrl, routeBasePath]);
57
+ const blogTagsListPath = (0, utils_1.normalizeUrl)([baseBlogUrl, tagsBasePath]);
57
58
  const blogPosts = await (0, blogUtils_1.generateBlogPosts)(contentPaths, context, options);
58
59
  if (!blogPosts.length) {
59
60
  return {
@@ -61,7 +62,7 @@ async function pluginContentBlog(context, options) {
61
62
  blogPosts: [],
62
63
  blogListPaginated: [],
63
64
  blogTags: {},
64
- blogTagsListPath: null,
65
+ blogTagsListPath,
65
66
  blogTagsPaginated: [],
66
67
  };
67
68
  }
@@ -82,7 +83,6 @@ async function pluginContentBlog(context, options) {
82
83
  };
83
84
  }
84
85
  });
85
- const baseBlogUrl = (0, utils_1.normalizeUrl)([baseUrl, routeBasePath]);
86
86
  const blogListPaginated = (0, blogUtils_1.paginateBlogPosts)({
87
87
  blogPosts,
88
88
  blogTitle,
@@ -96,8 +96,6 @@ async function pluginContentBlog(context, options) {
96
96
  blogDescription,
97
97
  blogTitle,
98
98
  });
99
- const tagsPath = (0, utils_1.normalizeUrl)([baseBlogUrl, tagsBasePath]);
100
- const blogTagsListPath = Object.keys(blogTags).length > 0 ? tagsPath : null;
101
99
  return {
102
100
  blogSidebarTitle,
103
101
  blogPosts,
@@ -117,13 +115,13 @@ async function pluginContentBlog(context, options) {
117
115
  const sidebarBlogPosts = options.blogSidebarCount === 'ALL'
118
116
  ? blogPosts
119
117
  : blogPosts.slice(0, options.blogSidebarCount);
120
- if (archiveBasePath) {
118
+ if (archiveBasePath && blogPosts.length) {
121
119
  const archiveUrl = (0, utils_1.normalizeUrl)([
122
120
  baseUrl,
123
121
  routeBasePath,
124
122
  archiveBasePath,
125
123
  ]);
126
- // creates a blog archive route
124
+ // Create a blog archive route
127
125
  const archiveProp = await createData(`${(0, utils_1.docuHash)(archiveUrl)}.json`, JSON.stringify({ blogPosts }, null, 2));
128
126
  addRoute({
129
127
  path: archiveUrl,
@@ -174,10 +172,7 @@ async function pluginContentBlog(context, options) {
174
172
  exact: true,
175
173
  modules: {
176
174
  sidebar: aliasedSource(sidebarProp),
177
- items: items.map((postID) =>
178
- // To tell routes.js this is an import and not a nested object
179
- // to recurse.
180
- ({
175
+ items: items.map((postID) => ({
181
176
  content: {
182
177
  __import: true,
183
178
  path: blogItemsToMetadata[postID].source,
@@ -190,24 +185,37 @@ async function pluginContentBlog(context, options) {
190
185
  },
191
186
  });
192
187
  }));
193
- // Tags.
194
- if (blogTagsListPath === null) {
188
+ // Tags. This is the last part so we early-return if there are no tags.
189
+ if (Object.keys(blogTags).length === 0) {
195
190
  return;
196
191
  }
197
- const tagsModule = Object.fromEntries(Object.entries(blogTags).map(([tagKey, tag]) => {
198
- const tagModule = {
199
- allTagsPath: blogTagsListPath,
200
- slug: tagKey,
201
- name: tag.name,
202
- count: tag.items.length,
192
+ async function createTagsListPage() {
193
+ const tagsProp = Object.values(blogTags).map((tag) => ({
194
+ label: tag.label,
203
195
  permalink: tag.permalink,
204
- };
205
- return [tag.name, tagModule];
206
- }));
207
- async function createTagRoutes(tag) {
196
+ count: tag.items.length,
197
+ }));
198
+ const tagsPropPath = await createData(`${(0, utils_1.docuHash)(`${blogTagsListPath}-tags`)}.json`, JSON.stringify(tagsProp, null, 2));
199
+ addRoute({
200
+ path: blogTagsListPath,
201
+ component: blogTagsListComponent,
202
+ exact: true,
203
+ modules: {
204
+ sidebar: aliasedSource(sidebarProp),
205
+ tags: aliasedSource(tagsPropPath),
206
+ },
207
+ });
208
+ }
209
+ async function createTagPostsListPage(tag) {
208
210
  await Promise.all(tag.pages.map(async (blogPaginated) => {
209
211
  const { metadata, items } = blogPaginated;
210
- const tagsMetadataPath = await createData(`${(0, utils_1.docuHash)(metadata.permalink)}.json`, JSON.stringify(tagsModule[tag.name], null, 2));
212
+ const tagProp = {
213
+ label: tag.label,
214
+ permalink: tag.permalink,
215
+ allTagsPath: blogTagsListPath,
216
+ count: tag.items.length,
217
+ };
218
+ const tagPropPath = await createData(`${(0, utils_1.docuHash)(metadata.permalink)}.json`, JSON.stringify(tagProp, null, 2));
211
219
  const listMetadataPath = await createData(`${(0, utils_1.docuHash)(metadata.permalink)}-list.json`, JSON.stringify(metadata, null, 2));
212
220
  addRoute({
213
221
  path: metadata.permalink,
@@ -227,26 +235,14 @@ async function pluginContentBlog(context, options) {
227
235
  },
228
236
  };
229
237
  }),
230
- metadata: aliasedSource(tagsMetadataPath),
238
+ tag: aliasedSource(tagPropPath),
231
239
  listMetadata: aliasedSource(listMetadataPath),
232
240
  },
233
241
  });
234
242
  }));
235
243
  }
236
- await Promise.all(Object.values(blogTags).map(createTagRoutes));
237
- // Only create /tags page if there are tags.
238
- if (Object.keys(blogTags).length > 0) {
239
- const tagsListPath = await createData(`${(0, utils_1.docuHash)(`${blogTagsListPath}-tags`)}.json`, JSON.stringify(tagsModule, null, 2));
240
- addRoute({
241
- path: blogTagsListPath,
242
- component: blogTagsListComponent,
243
- exact: true,
244
- modules: {
245
- sidebar: aliasedSource(sidebarProp),
246
- tags: aliasedSource(tagsListPath),
247
- },
248
- });
249
- }
244
+ await createTagsListPage();
245
+ await Promise.all(Object.values(blogTags).map(createTagPostsListPage));
250
246
  },
251
247
  translateContent({ content, translationFiles }) {
252
248
  return (0, translations_1.translateContent)(content, translationFiles);
@@ -286,7 +282,10 @@ async function pluginContentBlog(context, options) {
286
282
  options: {
287
283
  remarkPlugins,
288
284
  rehypePlugins,
289
- beforeDefaultRemarkPlugins,
285
+ beforeDefaultRemarkPlugins: [
286
+ footnoteIDFixer_1.default,
287
+ ...beforeDefaultRemarkPlugins,
288
+ ],
290
289
  beforeDefaultRehypePlugins,
291
290
  staticDirs: siteConfig.staticDirectories.map((dir) => path_1.default.resolve(siteDir, dir)),
292
291
  siteDir,
@@ -331,18 +330,18 @@ async function pluginContentBlog(context, options) {
331
330
  options,
332
331
  outDir,
333
332
  siteConfig,
333
+ locale: currentLocale,
334
334
  });
335
335
  },
336
336
  injectHtmlTags({ content }) {
337
- var _a, _b;
338
337
  if (!content.blogPosts.length) {
339
338
  return {};
340
339
  }
341
- if (!((_a = options.feedOptions) === null || _a === void 0 ? void 0 : _a.type)) {
340
+ if (!options.feedOptions?.type) {
342
341
  return {};
343
342
  }
344
343
  const feedTypes = options.feedOptions.type;
345
- const feedTitle = (_b = options.feedOptions.title) !== null && _b !== void 0 ? _b : context.siteConfig.title;
344
+ const feedTitle = options.feedOptions.title ?? context.siteConfig.title;
346
345
  const feedsConfig = {
347
346
  rss: {
348
347
  type: 'application/rss+xml',
@@ -362,11 +361,7 @@ async function pluginContentBlog(context, options) {
362
361
  };
363
362
  const headTags = [];
364
363
  feedTypes.forEach((feedType) => {
365
- const feedConfig = feedsConfig[feedType] || {};
366
- if (!feedsConfig) {
367
- return;
368
- }
369
- const { type, path: feedConfigPath, title: feedConfigTitle } = feedConfig;
364
+ const { type, path: feedConfigPath, title: feedConfigTitle, } = feedsConfig[feedType];
370
365
  headTags.push({
371
366
  tagName: 'link',
372
367
  attributes: {
@@ -388,8 +383,5 @@ async function pluginContentBlog(context, options) {
388
383
  };
389
384
  }
390
385
  exports.default = pluginContentBlog;
391
- function validateOptions({ validate, options, }) {
392
- const validatedOptions = validate(pluginOptionSchema_1.PluginOptionSchema, options);
393
- return validatedOptions;
394
- }
395
- exports.validateOptions = validateOptions;
386
+ var options_1 = require("./options");
387
+ Object.defineProperty(exports, "validateOptions", { enumerable: true, get: function () { return options_1.validateOptions; } });
@@ -25,6 +25,6 @@ function markdownLoader(source) {
25
25
  if (truncated) {
26
26
  finalContent = (0, blogUtils_1.truncate)(finalContent, markdownLoaderOptions.truncateMarker);
27
27
  }
28
- return callback && callback(null, finalContent);
28
+ return callback?.(null, finalContent);
29
29
  }
30
30
  exports.default = markdownLoader;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ import type { PluginOptions, Options } from '@docusaurus/plugin-content-blog';
8
+ import type { OptionValidationContext } from '@docusaurus/types';
9
+ export declare const DEFAULT_OPTIONS: PluginOptions;
10
+ export declare function validateOptions({ validate, options, }: OptionValidationContext<Options, PluginOptions>): PluginOptions;
@@ -6,7 +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.PluginOptionSchema = exports.DEFAULT_OPTIONS = void 0;
9
+ exports.validateOptions = exports.DEFAULT_OPTIONS = void 0;
10
10
  const utils_validation_1 = require("@docusaurus/utils-validation");
11
11
  const utils_1 = require("@docusaurus/utils");
12
12
  exports.DEFAULT_OPTIONS = {
@@ -39,7 +39,7 @@ exports.DEFAULT_OPTIONS = {
39
39
  readingTime: ({ content, defaultReadingTime }) => defaultReadingTime({ content }),
40
40
  sortPosts: 'descending',
41
41
  };
42
- exports.PluginOptionSchema = utils_validation_1.Joi.object({
42
+ const PluginOptionSchema = utils_validation_1.Joi.object({
43
43
  path: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.path),
44
44
  archiveBasePath: utils_validation_1.Joi.string()
45
45
  .default(exports.DEFAULT_OPTIONS.archiveBasePath)
@@ -85,7 +85,7 @@ exports.PluginOptionSchema = utils_validation_1.Joi.object({
85
85
  .default(exports.DEFAULT_OPTIONS.feedOptions.type),
86
86
  title: utils_validation_1.Joi.string().allow(''),
87
87
  description: utils_validation_1.Joi.string().allow(''),
88
- // only add default value when user actually wants a feed (type is not null)
88
+ // Only add default value when user actually wants a feed (type is not null)
89
89
  copyright: utils_validation_1.Joi.when('type', {
90
90
  is: utils_validation_1.Joi.any().valid(null),
91
91
  then: utils_validation_1.Joi.string().optional(),
@@ -100,4 +100,9 @@ exports.PluginOptionSchema = utils_validation_1.Joi.object({
100
100
  sortPosts: utils_validation_1.Joi.string()
101
101
  .valid('descending', 'ascending')
102
102
  .default(exports.DEFAULT_OPTIONS.sortPosts),
103
- });
103
+ }).default(exports.DEFAULT_OPTIONS);
104
+ function validateOptions({ validate, options, }) {
105
+ const validatedOptions = validate(PluginOptionSchema, options);
106
+ return validatedOptions;
107
+ }
108
+ exports.validateOptions = validateOptions;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ import type { Transformer } from 'unified';
8
+ /**
9
+ * In the blog list view, each post will be compiled separately. However, they
10
+ * may use the same footnote IDs. This leads to duplicated DOM IDs and inability
11
+ * to navigate to footnote references. This plugin fixes it by appending a
12
+ * unique hash to each reference/definition.
13
+ */
14
+ export default function plugin(): Transformer;