@docusaurus/plugin-content-blog 2.0.0-beta.15a2b59f9 → 2.0.0-beta.17

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