@docusaurus/plugin-content-blog 2.0.0-beta.fc64c12e4 → 2.0.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 (60) hide show
  1. package/lib/authors.d.ts +22 -0
  2. package/lib/authors.js +122 -0
  3. package/lib/blogUtils.d.ts +27 -7
  4. package/lib/blogUtils.js +201 -145
  5. package/lib/feed.d.ts +15 -0
  6. package/lib/feed.js +102 -0
  7. package/lib/frontMatter.d.ts +10 -0
  8. package/lib/{blogFrontMatter.js → frontMatter.js} +31 -19
  9. package/lib/index.d.ts +4 -4
  10. package/lib/index.js +163 -194
  11. package/lib/markdownLoader.d.ts +3 -6
  12. package/lib/markdownLoader.js +6 -7
  13. package/lib/options.d.ts +10 -0
  14. package/lib/{pluginOptionSchema.js → options.js} +41 -14
  15. package/lib/remark/footnoteIDFixer.d.ts +14 -0
  16. package/lib/remark/footnoteIDFixer.js +29 -0
  17. package/lib/translations.d.ts +10 -0
  18. package/lib/translations.js +53 -0
  19. package/lib/types.d.ts +4 -110
  20. package/package.json +23 -19
  21. package/src/authors.ts +168 -0
  22. package/src/blogUtils.ts +305 -205
  23. package/src/feed.ts +171 -0
  24. package/src/frontMatter.ts +81 -0
  25. package/src/index.ts +223 -258
  26. package/src/markdownLoader.ts +11 -16
  27. package/src/{pluginOptionSchema.ts → options.ts} +54 -16
  28. package/src/plugin-content-blog.d.ts +587 -0
  29. package/src/remark/footnoteIDFixer.ts +29 -0
  30. package/src/translations.ts +69 -0
  31. package/src/types.ts +2 -129
  32. package/index.d.ts +0 -138
  33. package/lib/.tsbuildinfo +0 -1
  34. package/lib/blogFrontMatter.d.ts +0 -28
  35. package/lib/pluginOptionSchema.d.ts +0 -34
  36. package/src/__tests__/__fixtures__/website/blog/2018-12-14-Happy-First-Birthday-Slash.md +0 -5
  37. package/src/__tests__/__fixtures__/website/blog/_partials/somePartial.md +0 -3
  38. package/src/__tests__/__fixtures__/website/blog/_partials/subfolder/somePartial.md +0 -3
  39. package/src/__tests__/__fixtures__/website/blog/_somePartial.md +0 -3
  40. package/src/__tests__/__fixtures__/website/blog/complex-slug.md +0 -7
  41. package/src/__tests__/__fixtures__/website/blog/date-matter.md +0 -5
  42. package/src/__tests__/__fixtures__/website/blog/draft.md +0 -6
  43. package/src/__tests__/__fixtures__/website/blog/heading-as-title.md +0 -5
  44. package/src/__tests__/__fixtures__/website/blog/simple-slug.md +0 -7
  45. package/src/__tests__/__fixtures__/website/blog-with-ref/2018-12-14-Happy-First-Birthday-Slash.md +0 -5
  46. package/src/__tests__/__fixtures__/website/blog-with-ref/post-with-broken-links.md +0 -11
  47. package/src/__tests__/__fixtures__/website/blog-with-ref/post.md +0 -5
  48. package/src/__tests__/__fixtures__/website/i18n/en/docusaurus-plugin-content-blog/2018-12-14-Happy-First-Birthday-Slash.md +0 -5
  49. package/src/__tests__/__fixtures__/website-blog-without-date/blog/no date.md +0 -1
  50. package/src/__tests__/__snapshots__/generateBlogFeed.test.ts.snap +0 -116
  51. package/src/__tests__/__snapshots__/linkify.test.ts.snap +0 -24
  52. package/src/__tests__/__snapshots__/pluginOptionSchema.test.ts.snap +0 -5
  53. package/src/__tests__/blogFrontMatter.test.ts +0 -317
  54. package/src/__tests__/generateBlogFeed.test.ts +0 -102
  55. package/src/__tests__/index.test.ts +0 -336
  56. package/src/__tests__/linkify.test.ts +0 -93
  57. package/src/__tests__/pluginOptionSchema.test.ts +0 -150
  58. package/src/blogFrontMatter.ts +0 -88
  59. package/tsconfig.json +0 -9
  60. package/types.d.ts +0 -13
package/lib/index.js CHANGED
@@ -8,53 +8,56 @@
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.validateOptions = void 0;
10
10
  const tslib_1 = require("tslib");
11
- const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
12
11
  const path_1 = tslib_1.__importDefault(require("path"));
13
- const remark_admonitions_1 = tslib_1.__importDefault(require("remark-admonitions"));
12
+ const logger_1 = tslib_1.__importDefault(require("@docusaurus/logger"));
14
13
  const utils_1 = require("@docusaurus/utils");
15
- const constants_1 = require("@docusaurus/core/lib/constants");
16
- const lodash_1 = require("lodash");
17
- const pluginOptionSchema_1 = require("./pluginOptionSchema");
18
14
  const blogUtils_1 = require("./blogUtils");
19
- function pluginContentBlog(context, options) {
20
- var _a;
21
- if (options.admonitions) {
22
- options.remarkPlugins = options.remarkPlugins.concat([
23
- [remark_admonitions_1.default, options.admonitions],
24
- ]);
25
- }
26
- const { siteDir, siteConfig: { onBrokenMarkdownLinks }, generatedFilesDir, i18n: { currentLocale }, } = context;
15
+ const footnoteIDFixer_1 = tslib_1.__importDefault(require("./remark/footnoteIDFixer"));
16
+ const translations_1 = require("./translations");
17
+ const feed_1 = require("./feed");
18
+ async function pluginContentBlog(context, options) {
19
+ const { siteDir, siteConfig, generatedFilesDir, localizationDir, i18n: { currentLocale }, } = context;
20
+ const { onBrokenMarkdownLinks, baseUrl } = siteConfig;
27
21
  const contentPaths = {
28
22
  contentPath: path_1.default.resolve(siteDir, options.path),
29
- contentPathLocalized: utils_1.getPluginI18nPath({
30
- siteDir,
31
- locale: currentLocale,
23
+ contentPathLocalized: (0, utils_1.getPluginI18nPath)({
24
+ localizationDir,
32
25
  pluginName: 'docusaurus-plugin-content-blog',
33
26
  pluginId: options.id,
34
27
  }),
35
28
  };
36
- const pluginId = (_a = options.id) !== null && _a !== void 0 ? _a : constants_1.DEFAULT_PLUGIN_ID;
29
+ const pluginId = options.id ?? utils_1.DEFAULT_PLUGIN_ID;
37
30
  const pluginDataDirRoot = path_1.default.join(generatedFilesDir, 'docusaurus-plugin-content-blog');
38
31
  const dataDir = path_1.default.join(pluginDataDirRoot, pluginId);
39
- const aliasedSource = (source) => `~blog/${utils_1.posixPath(path_1.default.relative(pluginDataDirRoot, source))}`;
32
+ const aliasedSource = (source) => `~blog/${(0, utils_1.posixPath)(path_1.default.relative(pluginDataDirRoot, source))}`;
33
+ const authorsMapFilePath = await (0, utils_1.getDataFilePath)({
34
+ filePath: options.authorsMapPath,
35
+ contentPaths,
36
+ });
40
37
  return {
41
38
  name: 'docusaurus-plugin-content-blog',
42
39
  getPathsToWatch() {
43
- const { include = [] } = options;
44
- return lodash_1.flatten(blogUtils_1.getContentPathList(contentPaths).map((contentPath) => {
45
- return include.map((pattern) => `${contentPath}/${pattern}`);
46
- }));
40
+ const { include } = options;
41
+ const contentMarkdownGlobs = (0, utils_1.getContentPathList)(contentPaths).flatMap((contentPath) => include.map((pattern) => `${contentPath}/${pattern}`));
42
+ return [authorsMapFilePath, ...contentMarkdownGlobs].filter(Boolean);
43
+ },
44
+ getTranslationFiles() {
45
+ return (0, translations_1.getTranslationFiles)(options);
47
46
  },
48
47
  // Fetches blog contents and returns metadata for the necessary routes.
49
48
  async loadContent() {
50
- const { postsPerPage, routeBasePath } = options;
51
- const blogPosts = await blogUtils_1.generateBlogPosts(contentPaths, context, options);
49
+ const { postsPerPage: postsPerPageOption, routeBasePath, tagsBasePath, blogDescription, blogTitle, blogSidebarTitle, } = options;
50
+ const baseBlogUrl = (0, utils_1.normalizeUrl)([baseUrl, routeBasePath]);
51
+ const blogTagsListPath = (0, utils_1.normalizeUrl)([baseBlogUrl, tagsBasePath]);
52
+ const blogPosts = await (0, blogUtils_1.generateBlogPosts)(contentPaths, context, options);
52
53
  if (!blogPosts.length) {
53
54
  return {
55
+ blogSidebarTitle,
54
56
  blogPosts: [],
55
57
  blogListPaginated: [],
56
58
  blogTags: {},
57
- blogTagsListPath: null,
59
+ blogTagsListPath,
60
+ blogTagsPaginated: [],
58
61
  };
59
62
  }
60
63
  // Colocate next and prev metadata.
@@ -74,72 +77,21 @@ function pluginContentBlog(context, options) {
74
77
  };
75
78
  }
76
79
  });
77
- // Blog pagination routes.
78
- // Example: `/blog`, `/blog/page/1`, `/blog/page/2`
79
- const totalCount = blogPosts.length;
80
- const numberOfPages = Math.ceil(totalCount / postsPerPage);
81
- const { siteConfig: { baseUrl = '' }, } = context;
82
- const basePageUrl = utils_1.normalizeUrl([baseUrl, routeBasePath]);
83
- const blogListPaginated = [];
84
- function blogPaginationPermalink(page) {
85
- return page > 0
86
- ? utils_1.normalizeUrl([basePageUrl, `page/${page + 1}`])
87
- : basePageUrl;
88
- }
89
- for (let page = 0; page < numberOfPages; page += 1) {
90
- blogListPaginated.push({
91
- metadata: {
92
- permalink: blogPaginationPermalink(page),
93
- page: page + 1,
94
- postsPerPage,
95
- totalPages: numberOfPages,
96
- totalCount,
97
- previousPage: page !== 0 ? blogPaginationPermalink(page - 1) : null,
98
- nextPage: page < numberOfPages - 1
99
- ? blogPaginationPermalink(page + 1)
100
- : null,
101
- blogDescription: options.blogDescription,
102
- blogTitle: options.blogTitle,
103
- },
104
- items: blogPosts
105
- .slice(page * postsPerPage, (page + 1) * postsPerPage)
106
- .map((item) => item.id),
107
- });
108
- }
109
- const blogTags = {};
110
- const tagsPath = utils_1.normalizeUrl([basePageUrl, 'tags']);
111
- blogPosts.forEach((blogPost) => {
112
- const { tags } = blogPost.metadata;
113
- if (!tags || tags.length === 0) {
114
- // TODO: Extract tags out into a separate plugin.
115
- // eslint-disable-next-line no-param-reassign
116
- blogPost.metadata.tags = [];
117
- return;
118
- }
119
- // eslint-disable-next-line no-param-reassign
120
- blogPost.metadata.tags = tags.map((tag) => {
121
- if (typeof tag === 'string') {
122
- const normalizedTag = lodash_1.kebabCase(tag);
123
- const permalink = utils_1.normalizeUrl([tagsPath, normalizedTag]);
124
- if (!blogTags[normalizedTag]) {
125
- blogTags[normalizedTag] = {
126
- // Will only use the name of the first occurrence of the tag.
127
- name: tag.toLowerCase(),
128
- items: [],
129
- permalink,
130
- };
131
- }
132
- blogTags[normalizedTag].items.push(blogPost.id);
133
- return {
134
- label: tag,
135
- permalink,
136
- };
137
- }
138
- return tag;
139
- });
80
+ const blogListPaginated = (0, blogUtils_1.paginateBlogPosts)({
81
+ blogPosts,
82
+ blogTitle,
83
+ blogDescription,
84
+ postsPerPageOption,
85
+ basePageUrl: baseBlogUrl,
86
+ });
87
+ const blogTags = (0, blogUtils_1.getBlogTags)({
88
+ blogPosts,
89
+ postsPerPageOption,
90
+ blogDescription,
91
+ blogTitle,
140
92
  });
141
- const blogTagsListPath = Object.keys(blogTags).length > 0 ? tagsPath : null;
142
93
  return {
94
+ blogSidebarTitle,
143
95
  blogPosts,
144
96
  blogListPaginated,
145
97
  blogTags,
@@ -147,22 +99,50 @@ function pluginContentBlog(context, options) {
147
99
  };
148
100
  },
149
101
  async contentLoaded({ content: blogContents, actions }) {
150
- if (!blogContents) {
151
- return;
152
- }
153
- const { blogListComponent, blogPostComponent, blogTagsListComponent, blogTagsPostsComponent, } = options;
102
+ const { blogListComponent, blogPostComponent, blogTagsListComponent, blogTagsPostsComponent, blogArchiveComponent, routeBasePath, archiveBasePath, } = options;
154
103
  const { addRoute, createData } = actions;
155
- const { blogPosts, blogListPaginated, blogTags, blogTagsListPath, } = blogContents;
104
+ const { blogSidebarTitle, blogPosts, blogListPaginated, blogTags, blogTagsListPath, } = blogContents;
156
105
  const blogItemsToMetadata = {};
157
106
  const sidebarBlogPosts = options.blogSidebarCount === 'ALL'
158
107
  ? blogPosts
159
- : lodash_1.take(blogPosts, options.blogSidebarCount);
108
+ : blogPosts.slice(0, options.blogSidebarCount);
109
+ function blogPostItemsModule(items) {
110
+ return items.map((postId) => {
111
+ const blogPostMetadata = blogItemsToMetadata[postId];
112
+ return {
113
+ content: {
114
+ __import: true,
115
+ path: blogPostMetadata.source,
116
+ query: {
117
+ truncated: true,
118
+ },
119
+ },
120
+ };
121
+ });
122
+ }
123
+ if (archiveBasePath && blogPosts.length) {
124
+ const archiveUrl = (0, utils_1.normalizeUrl)([
125
+ baseUrl,
126
+ routeBasePath,
127
+ archiveBasePath,
128
+ ]);
129
+ // Create a blog archive route
130
+ const archiveProp = await createData(`${(0, utils_1.docuHash)(archiveUrl)}.json`, JSON.stringify({ blogPosts }, null, 2));
131
+ addRoute({
132
+ path: archiveUrl,
133
+ component: blogArchiveComponent,
134
+ exact: true,
135
+ modules: {
136
+ archive: aliasedSource(archiveProp),
137
+ },
138
+ });
139
+ }
160
140
  // This prop is useful to provide the blog list sidebar
161
141
  const sidebarProp = await createData(
162
142
  // Note that this created data path must be in sync with
163
143
  // metadataPath provided to mdx-loader.
164
144
  `blog-post-list-prop-${pluginId}.json`, JSON.stringify({
165
- title: options.blogSidebarTitle,
145
+ title: blogSidebarTitle,
166
146
  items: sidebarBlogPosts.map((blogPost) => ({
167
147
  title: blogPost.metadata.title,
168
148
  permalink: blogPost.metadata.permalink,
@@ -174,7 +154,7 @@ function pluginContentBlog(context, options) {
174
154
  await createData(
175
155
  // Note that this created data path must be in sync with
176
156
  // metadataPath provided to mdx-loader.
177
- `${utils_1.docuHash(metadata.source)}.json`, JSON.stringify(metadata, null, 2));
157
+ `${(0, utils_1.docuHash)(metadata.source)}.json`, JSON.stringify(metadata, null, 2));
178
158
  addRoute({
179
159
  path: metadata.permalink,
180
160
  component: blogPostComponent,
@@ -190,95 +170,84 @@ function pluginContentBlog(context, options) {
190
170
  await Promise.all(blogListPaginated.map(async (listPage) => {
191
171
  const { metadata, items } = listPage;
192
172
  const { permalink } = metadata;
193
- const pageMetadataPath = await createData(`${utils_1.docuHash(permalink)}.json`, JSON.stringify(metadata, null, 2));
173
+ const pageMetadataPath = await createData(`${(0, utils_1.docuHash)(permalink)}.json`, JSON.stringify(metadata, null, 2));
194
174
  addRoute({
195
175
  path: permalink,
196
176
  component: blogListComponent,
197
177
  exact: true,
198
178
  modules: {
199
179
  sidebar: aliasedSource(sidebarProp),
200
- items: items.map((postID) => {
201
- // To tell routes.js this is an import and not a nested object to recurse.
202
- return {
203
- content: {
204
- __import: true,
205
- path: blogItemsToMetadata[postID].source,
206
- query: {
207
- truncated: true,
208
- },
209
- },
210
- };
211
- }),
180
+ items: blogPostItemsModule(items),
212
181
  metadata: aliasedSource(pageMetadataPath),
213
182
  },
214
183
  });
215
184
  }));
216
- // Tags.
217
- if (blogTagsListPath === null) {
185
+ // Tags. This is the last part so we early-return if there are no tags.
186
+ if (Object.keys(blogTags).length === 0) {
218
187
  return;
219
188
  }
220
- const tagsModule = {};
221
- await Promise.all(Object.keys(blogTags).map(async (tag) => {
222
- const { name, items, permalink } = blogTags[tag];
223
- tagsModule[tag] = {
224
- allTagsPath: blogTagsListPath,
225
- slug: tag,
226
- name,
227
- count: items.length,
228
- permalink,
229
- };
230
- const tagsMetadataPath = await createData(`${utils_1.docuHash(permalink)}.json`, JSON.stringify(tagsModule[tag], null, 2));
231
- addRoute({
232
- path: permalink,
233
- component: blogTagsPostsComponent,
234
- exact: true,
235
- modules: {
236
- sidebar: aliasedSource(sidebarProp),
237
- items: items.map((postID) => {
238
- const metadata = blogItemsToMetadata[postID];
239
- return {
240
- content: {
241
- __import: true,
242
- path: metadata.source,
243
- query: {
244
- truncated: true,
245
- },
246
- },
247
- };
248
- }),
249
- metadata: aliasedSource(tagsMetadataPath),
250
- },
251
- });
252
- }));
253
- // Only create /tags page if there are tags.
254
- if (Object.keys(blogTags).length > 0) {
255
- const tagsListPath = await createData(`${utils_1.docuHash(`${blogTagsListPath}-tags`)}.json`, JSON.stringify(tagsModule, null, 2));
189
+ async function createTagsListPage() {
190
+ const tagsProp = Object.values(blogTags).map((tag) => ({
191
+ label: tag.label,
192
+ permalink: tag.permalink,
193
+ count: tag.items.length,
194
+ }));
195
+ const tagsPropPath = await createData(`${(0, utils_1.docuHash)(`${blogTagsListPath}-tags`)}.json`, JSON.stringify(tagsProp, null, 2));
256
196
  addRoute({
257
197
  path: blogTagsListPath,
258
198
  component: blogTagsListComponent,
259
199
  exact: true,
260
200
  modules: {
261
201
  sidebar: aliasedSource(sidebarProp),
262
- tags: aliasedSource(tagsListPath),
202
+ tags: aliasedSource(tagsPropPath),
263
203
  },
264
204
  });
265
205
  }
206
+ async function createTagPostsListPage(tag) {
207
+ await Promise.all(tag.pages.map(async (blogPaginated) => {
208
+ const { metadata, items } = blogPaginated;
209
+ const tagProp = {
210
+ label: tag.label,
211
+ permalink: tag.permalink,
212
+ allTagsPath: blogTagsListPath,
213
+ count: tag.items.length,
214
+ };
215
+ const tagPropPath = await createData(`${(0, utils_1.docuHash)(metadata.permalink)}.json`, JSON.stringify(tagProp, null, 2));
216
+ const listMetadataPath = await createData(`${(0, utils_1.docuHash)(metadata.permalink)}-list.json`, JSON.stringify(metadata, null, 2));
217
+ addRoute({
218
+ path: metadata.permalink,
219
+ component: blogTagsPostsComponent,
220
+ exact: true,
221
+ modules: {
222
+ sidebar: aliasedSource(sidebarProp),
223
+ items: blogPostItemsModule(items),
224
+ tag: aliasedSource(tagPropPath),
225
+ listMetadata: aliasedSource(listMetadataPath),
226
+ },
227
+ });
228
+ }));
229
+ }
230
+ await createTagsListPage();
231
+ await Promise.all(Object.values(blogTags).map(createTagPostsListPage));
232
+ },
233
+ translateContent({ content, translationFiles }) {
234
+ return (0, translations_1.translateContent)(content, translationFiles);
266
235
  },
267
236
  configureWebpack(_config, isServer, { getJSLoader }, content) {
268
- const { rehypePlugins, remarkPlugins, truncateMarker, beforeDefaultRemarkPlugins, beforeDefaultRehypePlugins, } = options;
237
+ const { admonitions, rehypePlugins, remarkPlugins, truncateMarker, beforeDefaultRemarkPlugins, beforeDefaultRehypePlugins, } = options;
269
238
  const markdownLoaderOptions = {
270
239
  siteDir,
271
240
  contentPaths,
272
241
  truncateMarker,
273
- sourceToPermalink: blogUtils_1.getSourceToPermalink(content.blogPosts),
242
+ sourceToPermalink: (0, blogUtils_1.getSourceToPermalink)(content.blogPosts),
274
243
  onBrokenMarkdownLink: (brokenMarkdownLink) => {
275
244
  if (onBrokenMarkdownLinks === 'ignore') {
276
245
  return;
277
246
  }
278
- utils_1.reportMessage(`Blog markdown link couldn't be resolved: (${brokenMarkdownLink.link}) in ${brokenMarkdownLink.filePath}`, onBrokenMarkdownLinks);
247
+ logger_1.default.report(onBrokenMarkdownLinks) `Blog markdown link couldn't be resolved: (url=${brokenMarkdownLink.link}) in path=${brokenMarkdownLink.filePath}`;
279
248
  },
280
249
  };
281
- const contentDirs = blogUtils_1.getContentPathList(contentPaths);
250
+ const contentDirs = (0, utils_1.getContentPathList)(contentPaths);
282
251
  return {
283
252
  resolve: {
284
253
  alias: {
@@ -288,7 +257,7 @@ function pluginContentBlog(context, options) {
288
257
  module: {
289
258
  rules: [
290
259
  {
291
- test: /(\.mdx?)$/,
260
+ test: /\.mdx?$/i,
292
261
  include: contentDirs
293
262
  // Trailing slash is important, see https://github.com/facebook/docusaurus/pull/3970
294
263
  .map(utils_1.addTrailingPathSeparator),
@@ -297,21 +266,32 @@ function pluginContentBlog(context, options) {
297
266
  {
298
267
  loader: require.resolve('@docusaurus/mdx-loader'),
299
268
  options: {
269
+ admonitions,
300
270
  remarkPlugins,
301
271
  rehypePlugins,
302
- beforeDefaultRemarkPlugins,
272
+ beforeDefaultRemarkPlugins: [
273
+ footnoteIDFixer_1.default,
274
+ ...beforeDefaultRemarkPlugins,
275
+ ],
303
276
  beforeDefaultRehypePlugins,
304
- staticDir: path_1.default.join(siteDir, constants_1.STATIC_DIR_NAME),
305
- isMDXPartial: utils_1.createAbsoluteFilePathMatcher(options.exclude, contentDirs),
277
+ staticDirs: siteConfig.staticDirectories.map((dir) => path_1.default.resolve(siteDir, dir)),
278
+ siteDir,
279
+ isMDXPartial: (0, utils_1.createAbsoluteFilePathMatcher)(options.exclude, contentDirs),
306
280
  metadataPath: (mdxPath) => {
307
281
  // Note that metadataPath must be the same/in-sync as
308
282
  // the path from createData for each MDX.
309
- const aliasedPath = utils_1.aliasedSitePath(mdxPath, siteDir);
310
- return path_1.default.join(dataDir, `${utils_1.docuHash(aliasedPath)}.json`);
283
+ const aliasedPath = (0, utils_1.aliasedSitePath)(mdxPath, siteDir);
284
+ return path_1.default.join(dataDir, `${(0, utils_1.docuHash)(aliasedPath)}.json`);
311
285
  },
312
286
  // For blog posts a title in markdown is always removed
313
287
  // Blog posts title are rendered separately
314
288
  removeContentTitle: true,
289
+ // Assets allow to convert some relative images paths to
290
+ // require() calls
291
+ createAssets: ({ frontMatter, metadata, }) => ({
292
+ image: frontMatter.image,
293
+ authorsImageUrls: metadata.authors.map((author) => author.imageURL),
294
+ }),
315
295
  },
316
296
  },
317
297
  {
@@ -324,62 +304,54 @@ function pluginContentBlog(context, options) {
324
304
  },
325
305
  };
326
306
  },
327
- async postBuild({ outDir }) {
328
- var _a;
329
- if (!((_a = options.feedOptions) === null || _a === void 0 ? void 0 : _a.type)) {
307
+ async postBuild({ outDir, content }) {
308
+ if (!options.feedOptions.type) {
330
309
  return;
331
310
  }
332
- const feed = await blogUtils_1.generateBlogFeed(contentPaths, context, options);
333
- if (!feed) {
311
+ const { blogPosts } = content;
312
+ if (!blogPosts.length) {
334
313
  return;
335
314
  }
336
- const feedTypes = options.feedOptions.type;
337
- await Promise.all(feedTypes.map(async (feedType) => {
338
- const feedPath = path_1.default.join(outDir, options.routeBasePath, `${feedType}.xml`);
339
- const feedContent = feedType === 'rss' ? feed.rss2() : feed.atom1();
340
- try {
341
- await fs_extra_1.default.outputFile(feedPath, feedContent);
342
- }
343
- catch (err) {
344
- throw new Error(`Generating ${feedType} feed failed: ${err}.`);
345
- }
346
- }));
315
+ await (0, feed_1.createBlogFeedFiles)({
316
+ blogPosts,
317
+ options,
318
+ outDir,
319
+ siteConfig,
320
+ locale: currentLocale,
321
+ });
347
322
  },
348
323
  injectHtmlTags({ content }) {
349
- var _a;
350
- if (!content.blogPosts.length) {
351
- return {};
352
- }
353
- if (!((_a = options.feedOptions) === null || _a === void 0 ? void 0 : _a.type)) {
324
+ if (!content.blogPosts.length || !options.feedOptions.type) {
354
325
  return {};
355
326
  }
356
327
  const feedTypes = options.feedOptions.type;
357
- const { siteConfig: { title }, baseUrl, } = context;
328
+ const feedTitle = options.feedOptions.title ?? context.siteConfig.title;
358
329
  const feedsConfig = {
359
330
  rss: {
360
331
  type: 'application/rss+xml',
361
332
  path: 'rss.xml',
362
- title: `${title} Blog RSS Feed`,
333
+ title: `${feedTitle} RSS Feed`,
363
334
  },
364
335
  atom: {
365
336
  type: 'application/atom+xml',
366
337
  path: 'atom.xml',
367
- title: `${title} Blog Atom Feed`,
338
+ title: `${feedTitle} Atom Feed`,
339
+ },
340
+ json: {
341
+ type: 'application/json',
342
+ path: 'feed.json',
343
+ title: `${feedTitle} JSON Feed`,
368
344
  },
369
345
  };
370
346
  const headTags = [];
371
347
  feedTypes.forEach((feedType) => {
372
- const feedConfig = feedsConfig[feedType] || {};
373
- if (!feedsConfig) {
374
- return;
375
- }
376
- const { type, path: feedConfigPath, title: feedConfigTitle } = feedConfig;
348
+ const { type, path: feedConfigPath, title: feedConfigTitle, } = feedsConfig[feedType];
377
349
  headTags.push({
378
350
  tagName: 'link',
379
351
  attributes: {
380
352
  rel: 'alternate',
381
353
  type,
382
- href: utils_1.normalizeUrl([
354
+ href: (0, utils_1.normalizeUrl)([
383
355
  baseUrl,
384
356
  options.routeBasePath,
385
357
  feedConfigPath,
@@ -395,8 +367,5 @@ function pluginContentBlog(context, options) {
395
367
  };
396
368
  }
397
369
  exports.default = pluginContentBlog;
398
- function validateOptions({ validate, options, }) {
399
- const validatedOptions = validate(pluginOptionSchema_1.PluginOptionSchema, options);
400
- return validatedOptions;
401
- }
402
- exports.validateOptions = validateOptions;
370
+ var options_1 = require("./options");
371
+ Object.defineProperty(exports, "validateOptions", { enumerable: true, get: function () { return options_1.validateOptions; } });
@@ -4,9 +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 types="node" />
8
- interface Loader extends Function {
9
- (this: any, source: string): string | Buffer | void | undefined;
10
- }
11
- declare const markdownLoader: Loader;
12
- export default markdownLoader;
7
+ import type { BlogMarkdownLoaderOptions } from './types';
8
+ import type { LoaderContext } from 'webpack';
9
+ export default function markdownLoader(this: LoaderContext<BlogMarkdownLoaderOptions>, source: string): void;
@@ -7,25 +7,24 @@
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  const blogUtils_1 = require("./blogUtils");
10
- const loader_utils_1 = require("loader-utils");
11
- const markdownLoader = function (source) {
10
+ function markdownLoader(source) {
12
11
  const filePath = this.resourcePath;
13
12
  const fileString = source;
14
13
  const callback = this.async();
15
14
  const markdownLoaderOptions = this.getOptions();
16
15
  // Linkify blog posts
17
- let finalContent = blogUtils_1.linkify({
16
+ let finalContent = (0, blogUtils_1.linkify)({
18
17
  fileString,
19
18
  filePath,
20
19
  ...markdownLoaderOptions,
21
20
  });
22
21
  // Truncate content if requested (e.g: file.md?truncated=true).
23
22
  const truncated = this.resourceQuery
24
- ? !!loader_utils_1.parseQuery(this.resourceQuery).truncated
23
+ ? !!new URLSearchParams(this.resourceQuery.slice(1)).get('truncated')
25
24
  : undefined;
26
25
  if (truncated) {
27
- finalContent = blogUtils_1.truncate(finalContent, markdownLoaderOptions.truncateMarker);
26
+ finalContent = (0, blogUtils_1.truncate)(finalContent, markdownLoaderOptions.truncateMarker);
28
27
  }
29
- return callback && callback(null, finalContent);
30
- };
28
+ return callback(null, finalContent);
29
+ }
31
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 | undefined, PluginOptions>): PluginOptions;