@docusaurus/plugin-content-blog 2.0.0-beta.12faed89d → 2.0.0-beta.13

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 (65) hide show
  1. package/lib/.tsbuildinfo +1 -1
  2. package/lib/authors.d.ts +23 -0
  3. package/lib/authors.js +147 -0
  4. package/lib/blogFrontMatter.d.ts +19 -6
  5. package/lib/blogFrontMatter.js +31 -19
  6. package/lib/blogUtils.d.ts +10 -4
  7. package/lib/blogUtils.js +141 -136
  8. package/lib/feed.d.ts +20 -0
  9. package/lib/feed.js +90 -0
  10. package/lib/index.js +99 -106
  11. package/lib/markdownLoader.d.ts +3 -6
  12. package/lib/markdownLoader.js +5 -5
  13. package/lib/pluginOptionSchema.d.ts +3 -26
  14. package/lib/pluginOptionSchema.js +28 -7
  15. package/lib/translations.d.ts +10 -0
  16. package/lib/translations.js +53 -0
  17. package/lib/types.d.ts +54 -14
  18. package/package.json +17 -13
  19. package/src/__tests__/__fixtures__/authorsMapFiles/authors.json +29 -0
  20. package/src/__tests__/__fixtures__/authorsMapFiles/authors.yml +27 -0
  21. package/src/__tests__/__fixtures__/authorsMapFiles/authorsBad1.json +5 -0
  22. package/src/__tests__/__fixtures__/authorsMapFiles/authorsBad1.yml +3 -0
  23. package/src/__tests__/__fixtures__/authorsMapFiles/authorsBad2.json +3 -0
  24. package/src/__tests__/__fixtures__/authorsMapFiles/authorsBad2.yml +2 -0
  25. package/src/__tests__/__fixtures__/authorsMapFiles/authorsBad3.json +8 -0
  26. package/src/__tests__/__fixtures__/authorsMapFiles/authorsBad3.yml +3 -0
  27. package/src/__tests__/__fixtures__/component/Typography.tsx +6 -0
  28. package/src/__tests__/__fixtures__/getAuthorsMapFilePath/contentPathEmpty/empty +0 -0
  29. package/src/__tests__/__fixtures__/getAuthorsMapFilePath/contentPathJson1/authors.json +0 -0
  30. package/src/__tests__/__fixtures__/getAuthorsMapFilePath/contentPathJson2/authors.json +0 -0
  31. package/src/__tests__/__fixtures__/getAuthorsMapFilePath/contentPathNestedYml/sub/folder/authors.yml +0 -0
  32. package/src/__tests__/__fixtures__/getAuthorsMapFilePath/contentPathYml1/authors.yml +0 -0
  33. package/src/__tests__/__fixtures__/getAuthorsMapFilePath/contentPathYml2/authors.yml +0 -0
  34. package/src/__tests__/__fixtures__/website/blog/2018-12-14-Happy-First-Birthday-Slash.md +3 -0
  35. package/src/__tests__/__fixtures__/website/blog/_partials/somePartial.md +3 -0
  36. package/src/__tests__/__fixtures__/website/blog/_partials/subfolder/somePartial.md +3 -0
  37. package/src/__tests__/__fixtures__/website/blog/_somePartial.md +3 -0
  38. package/src/__tests__/__fixtures__/website/blog/authors.yml +4 -0
  39. package/src/__tests__/__fixtures__/website/blog/mdx-blog-post.mdx +36 -0
  40. package/src/__tests__/__fixtures__/website/blog/mdx-require-blog-post.mdx +14 -0
  41. package/src/__tests__/__fixtures__/website/blog/simple-slug.md +4 -0
  42. package/src/__tests__/__fixtures__/website/i18n/en/docusaurus-plugin-content-blog/2018-12-14-Happy-First-Birthday-Slash.md +3 -0
  43. package/src/__tests__/__fixtures__/website/i18n/en/docusaurus-plugin-content-blog/authors.yml +5 -0
  44. package/src/__tests__/__fixtures__/website/static/img/docusaurus.png +0 -0
  45. package/src/__tests__/__snapshots__/feed.test.ts.snap +164 -0
  46. package/src/__tests__/__snapshots__/translations.test.ts.snap +64 -0
  47. package/src/__tests__/authors.test.ts +608 -0
  48. package/src/__tests__/blogFrontMatter.test.ts +93 -16
  49. package/src/__tests__/blogUtils.test.ts +94 -0
  50. package/src/__tests__/{generateBlogFeed.test.ts → feed.test.ts} +35 -9
  51. package/src/__tests__/index.test.ts +84 -12
  52. package/src/__tests__/pluginOptionSchema.test.ts +3 -3
  53. package/src/__tests__/translations.test.ts +92 -0
  54. package/src/authors.ts +198 -0
  55. package/src/blogFrontMatter.ts +71 -33
  56. package/src/blogUtils.ts +202 -179
  57. package/{types.d.ts → src/deps.d.ts} +0 -0
  58. package/src/feed.ts +129 -0
  59. package/src/index.ts +118 -107
  60. package/src/markdownLoader.ts +8 -12
  61. package/{index.d.ts → src/plugin-content-blog.d.ts} +35 -31
  62. package/src/pluginOptionSchema.ts +31 -9
  63. package/src/translations.ts +63 -0
  64. package/src/types.ts +69 -16
  65. package/src/__tests__/__snapshots__/generateBlogFeed.test.ts.snap +0 -76
package/lib/index.js CHANGED
@@ -8,14 +8,13 @@
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
- const path_1 = tslib_1.__importDefault(require("path"));
13
- const remark_admonitions_1 = tslib_1.__importDefault(require("remark-admonitions"));
11
+ const path_1 = (0, tslib_1.__importDefault)(require("path"));
12
+ const remark_admonitions_1 = (0, 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");
17
+ const feed_1 = require("./feed");
19
18
  function pluginContentBlog(context, options) {
20
19
  var _a;
21
20
  if (options.admonitions) {
@@ -23,41 +22,42 @@ function pluginContentBlog(context, options) {
23
22
  [remark_admonitions_1.default, options.admonitions],
24
23
  ]);
25
24
  }
26
- const { siteDir, siteConfig: { onBrokenMarkdownLinks }, generatedFilesDir, i18n: { currentLocale }, } = context;
25
+ const { siteDir, siteConfig, generatedFilesDir, i18n: { currentLocale }, } = context;
26
+ const { onBrokenMarkdownLinks, baseUrl } = siteConfig;
27
27
  const contentPaths = {
28
28
  contentPath: path_1.default.resolve(siteDir, options.path),
29
- contentPathLocalized: utils_1.getPluginI18nPath({
29
+ contentPathLocalized: (0, utils_1.getPluginI18nPath)({
30
30
  siteDir,
31
31
  locale: currentLocale,
32
32
  pluginName: 'docusaurus-plugin-content-blog',
33
33
  pluginId: options.id,
34
34
  }),
35
35
  };
36
- const pluginId = (_a = options.id) !== null && _a !== void 0 ? _a : constants_1.DEFAULT_PLUGIN_ID;
36
+ const pluginId = (_a = options.id) !== null && _a !== void 0 ? _a : utils_1.DEFAULT_PLUGIN_ID;
37
37
  const pluginDataDirRoot = path_1.default.join(generatedFilesDir, 'docusaurus-plugin-content-blog');
38
38
  const dataDir = path_1.default.join(pluginDataDirRoot, pluginId);
39
- const aliasedSource = (source) => `~blog/${utils_1.posixPath(path_1.default.relative(pluginDataDirRoot, source))}`;
39
+ const aliasedSource = (source) => `~blog/${(0, utils_1.posixPath)(path_1.default.relative(pluginDataDirRoot, source))}`;
40
40
  return {
41
41
  name: 'docusaurus-plugin-content-blog',
42
42
  getPathsToWatch() {
43
- const { include = [] } = options;
44
- return lodash_1.flatten(blogUtils_1.getContentPathList(contentPaths).map((contentPath) => {
45
- return include.map((pattern) => `${contentPath}/${pattern}`);
46
- }));
43
+ const { include, authorsMapPath } = options;
44
+ const contentMarkdownGlobs = (0, blogUtils_1.getContentPathList)(contentPaths).flatMap((contentPath) => include.map((pattern) => `${contentPath}/${pattern}`));
45
+ // TODO: we should read this path in plugin! but plugins do not support async init for now :'(
46
+ // const authorsMapFilePath = await getAuthorsMapFilePath({authorsMapPath,contentPaths,});
47
+ // simplified impl, better than nothing for now:
48
+ const authorsMapFilePath = path_1.default.join(contentPaths.contentPath, authorsMapPath);
49
+ return [authorsMapFilePath, ...contentMarkdownGlobs];
47
50
  },
48
- getClientModules() {
49
- const modules = [];
50
- if (options.admonitions) {
51
- modules.push(require.resolve('remark-admonitions/styles/infima.css'));
52
- }
53
- return modules;
51
+ async getTranslationFiles() {
52
+ return (0, translations_1.getTranslationFiles)(options);
54
53
  },
55
54
  // Fetches blog contents and returns metadata for the necessary routes.
56
55
  async loadContent() {
57
- const { postsPerPage, routeBasePath } = options;
58
- const blogPosts = await blogUtils_1.generateBlogPosts(contentPaths, context, options);
56
+ const { postsPerPage: postsPerPageOption, routeBasePath, tagsBasePath, blogDescription, blogTitle, blogSidebarTitle, } = options;
57
+ const blogPosts = await (0, blogUtils_1.generateBlogPosts)(contentPaths, context, options);
59
58
  if (!blogPosts.length) {
60
59
  return {
60
+ blogSidebarTitle,
61
61
  blogPosts: [],
62
62
  blogListPaginated: [],
63
63
  blogTags: {},
@@ -84,14 +84,14 @@ function pluginContentBlog(context, options) {
84
84
  // Blog pagination routes.
85
85
  // Example: `/blog`, `/blog/page/1`, `/blog/page/2`
86
86
  const totalCount = blogPosts.length;
87
+ const postsPerPage = postsPerPageOption === 'ALL' ? totalCount : postsPerPageOption;
87
88
  const numberOfPages = Math.ceil(totalCount / postsPerPage);
88
- const { siteConfig: { baseUrl = '' }, } = context;
89
- const basePageUrl = utils_1.normalizeUrl([baseUrl, routeBasePath]);
89
+ const baseBlogUrl = (0, utils_1.normalizeUrl)([baseUrl, routeBasePath]);
90
90
  const blogListPaginated = [];
91
91
  function blogPaginationPermalink(page) {
92
92
  return page > 0
93
- ? utils_1.normalizeUrl([basePageUrl, `page/${page + 1}`])
94
- : basePageUrl;
93
+ ? (0, utils_1.normalizeUrl)([baseBlogUrl, `page/${page + 1}`])
94
+ : baseBlogUrl;
95
95
  }
96
96
  for (let page = 0; page < numberOfPages; page += 1) {
97
97
  blogListPaginated.push({
@@ -105,48 +105,19 @@ function pluginContentBlog(context, options) {
105
105
  nextPage: page < numberOfPages - 1
106
106
  ? blogPaginationPermalink(page + 1)
107
107
  : null,
108
- blogDescription: options.blogDescription,
109
- blogTitle: options.blogTitle,
108
+ blogDescription,
109
+ blogTitle,
110
110
  },
111
111
  items: blogPosts
112
112
  .slice(page * postsPerPage, (page + 1) * postsPerPage)
113
113
  .map((item) => item.id),
114
114
  });
115
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
- });
147
- });
116
+ const blogTags = (0, blogUtils_1.getBlogTags)(blogPosts);
117
+ const tagsPath = (0, utils_1.normalizeUrl)([baseBlogUrl, tagsBasePath]);
148
118
  const blogTagsListPath = Object.keys(blogTags).length > 0 ? tagsPath : null;
149
119
  return {
120
+ blogSidebarTitle,
150
121
  blogPosts,
151
122
  blogListPaginated,
152
123
  blogTags,
@@ -157,19 +128,34 @@ function pluginContentBlog(context, options) {
157
128
  if (!blogContents) {
158
129
  return;
159
130
  }
160
- const { blogListComponent, blogPostComponent, blogTagsListComponent, blogTagsPostsComponent, } = options;
131
+ const { blogListComponent, blogPostComponent, blogTagsListComponent, blogTagsPostsComponent, routeBasePath, archiveBasePath, } = options;
161
132
  const { addRoute, createData } = actions;
162
- const { blogPosts, blogListPaginated, blogTags, blogTagsListPath, } = blogContents;
133
+ const { blogSidebarTitle, blogPosts, blogListPaginated, blogTags, blogTagsListPath, } = blogContents;
163
134
  const blogItemsToMetadata = {};
164
135
  const sidebarBlogPosts = options.blogSidebarCount === 'ALL'
165
136
  ? blogPosts
166
- : lodash_1.take(blogPosts, options.blogSidebarCount);
137
+ : blogPosts.slice(0, options.blogSidebarCount);
138
+ const archiveUrl = (0, utils_1.normalizeUrl)([
139
+ baseUrl,
140
+ routeBasePath,
141
+ archiveBasePath,
142
+ ]);
143
+ // creates a blog archive route
144
+ const archiveProp = await createData(`${(0, utils_1.docuHash)(archiveUrl)}.json`, JSON.stringify({ blogPosts }, null, 2));
145
+ addRoute({
146
+ path: archiveUrl,
147
+ component: '@theme/BlogArchivePage',
148
+ exact: true,
149
+ modules: {
150
+ archive: aliasedSource(archiveProp),
151
+ },
152
+ });
167
153
  // This prop is useful to provide the blog list sidebar
168
154
  const sidebarProp = await createData(
169
155
  // Note that this created data path must be in sync with
170
156
  // metadataPath provided to mdx-loader.
171
157
  `blog-post-list-prop-${pluginId}.json`, JSON.stringify({
172
- title: options.blogSidebarTitle,
158
+ title: blogSidebarTitle,
173
159
  items: sidebarBlogPosts.map((blogPost) => ({
174
160
  title: blogPost.metadata.title,
175
161
  permalink: blogPost.metadata.permalink,
@@ -181,7 +167,7 @@ function pluginContentBlog(context, options) {
181
167
  await createData(
182
168
  // Note that this created data path must be in sync with
183
169
  // metadataPath provided to mdx-loader.
184
- `${utils_1.docuHash(metadata.source)}.json`, JSON.stringify(metadata, null, 2));
170
+ `${(0, utils_1.docuHash)(metadata.source)}.json`, JSON.stringify(metadata, null, 2));
185
171
  addRoute({
186
172
  path: metadata.permalink,
187
173
  component: blogPostComponent,
@@ -197,25 +183,24 @@ function pluginContentBlog(context, options) {
197
183
  await Promise.all(blogListPaginated.map(async (listPage) => {
198
184
  const { metadata, items } = listPage;
199
185
  const { permalink } = metadata;
200
- const pageMetadataPath = await createData(`${utils_1.docuHash(permalink)}.json`, JSON.stringify(metadata, null, 2));
186
+ const pageMetadataPath = await createData(`${(0, utils_1.docuHash)(permalink)}.json`, JSON.stringify(metadata, null, 2));
201
187
  addRoute({
202
188
  path: permalink,
203
189
  component: blogListComponent,
204
190
  exact: true,
205
191
  modules: {
206
192
  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
- },
193
+ items: items.map((postID) =>
194
+ // To tell routes.js this is an import and not a nested object to recurse.
195
+ ({
196
+ content: {
197
+ __import: true,
198
+ path: blogItemsToMetadata[postID].source,
199
+ query: {
200
+ truncated: true,
216
201
  },
217
- };
218
- }),
202
+ },
203
+ })),
219
204
  metadata: aliasedSource(pageMetadataPath),
220
205
  },
221
206
  });
@@ -227,6 +212,7 @@ function pluginContentBlog(context, options) {
227
212
  const tagsModule = {};
228
213
  await Promise.all(Object.keys(blogTags).map(async (tag) => {
229
214
  const { name, items, permalink } = blogTags[tag];
215
+ // Refactor all this, see docs implementation
230
216
  tagsModule[tag] = {
231
217
  allTagsPath: blogTagsListPath,
232
218
  slug: tag,
@@ -234,7 +220,7 @@ function pluginContentBlog(context, options) {
234
220
  count: items.length,
235
221
  permalink,
236
222
  };
237
- const tagsMetadataPath = await createData(`${utils_1.docuHash(permalink)}.json`, JSON.stringify(tagsModule[tag], null, 2));
223
+ const tagsMetadataPath = await createData(`${(0, utils_1.docuHash)(permalink)}.json`, JSON.stringify(tagsModule[tag], null, 2));
238
224
  addRoute({
239
225
  path: permalink,
240
226
  component: blogTagsPostsComponent,
@@ -259,7 +245,7 @@ function pluginContentBlog(context, options) {
259
245
  }));
260
246
  // Only create /tags page if there are tags.
261
247
  if (Object.keys(blogTags).length > 0) {
262
- const tagsListPath = await createData(`${utils_1.docuHash(`${blogTagsListPath}-tags`)}.json`, JSON.stringify(tagsModule, null, 2));
248
+ const tagsListPath = await createData(`${(0, utils_1.docuHash)(`${blogTagsListPath}-tags`)}.json`, JSON.stringify(tagsModule, null, 2));
263
249
  addRoute({
264
250
  path: blogTagsListPath,
265
251
  component: blogTagsListComponent,
@@ -271,20 +257,24 @@ function pluginContentBlog(context, options) {
271
257
  });
272
258
  }
273
259
  },
260
+ translateContent({ content, translationFiles }) {
261
+ return (0, translations_1.translateContent)(content, translationFiles);
262
+ },
274
263
  configureWebpack(_config, isServer, { getJSLoader }, content) {
275
264
  const { rehypePlugins, remarkPlugins, truncateMarker, beforeDefaultRemarkPlugins, beforeDefaultRehypePlugins, } = options;
276
265
  const markdownLoaderOptions = {
277
266
  siteDir,
278
267
  contentPaths,
279
268
  truncateMarker,
280
- sourceToPermalink: blogUtils_1.getSourceToPermalink(content.blogPosts),
269
+ sourceToPermalink: (0, blogUtils_1.getSourceToPermalink)(content.blogPosts),
281
270
  onBrokenMarkdownLink: (brokenMarkdownLink) => {
282
271
  if (onBrokenMarkdownLinks === 'ignore') {
283
272
  return;
284
273
  }
285
- utils_1.reportMessage(`Blog markdown link couldn't be resolved: (${brokenMarkdownLink.link}) in ${brokenMarkdownLink.filePath}`, onBrokenMarkdownLinks);
274
+ (0, utils_1.reportMessage)(`Blog markdown link couldn't be resolved: (${brokenMarkdownLink.link}) in ${brokenMarkdownLink.filePath}`, onBrokenMarkdownLinks);
286
275
  },
287
276
  };
277
+ const contentDirs = (0, blogUtils_1.getContentPathList)(contentPaths);
288
278
  return {
289
279
  resolve: {
290
280
  alias: {
@@ -295,7 +285,7 @@ function pluginContentBlog(context, options) {
295
285
  rules: [
296
286
  {
297
287
  test: /(\.mdx?)$/,
298
- include: blogUtils_1.getContentPathList(contentPaths)
288
+ include: contentDirs
299
289
  // Trailing slash is important, see https://github.com/facebook/docusaurus/pull/3970
300
290
  .map(utils_1.addTrailingPathSeparator),
301
291
  use: [
@@ -307,16 +297,23 @@ function pluginContentBlog(context, options) {
307
297
  rehypePlugins,
308
298
  beforeDefaultRemarkPlugins,
309
299
  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.
300
+ staticDirs: siteConfig.staticDirectories.map((dir) => path_1.default.resolve(siteDir, dir)),
301
+ siteDir,
302
+ isMDXPartial: (0, utils_1.createAbsoluteFilePathMatcher)(options.exclude, contentDirs),
313
303
  metadataPath: (mdxPath) => {
314
- const aliasedPath = utils_1.aliasedSitePath(mdxPath, siteDir);
315
- return path_1.default.join(dataDir, `${utils_1.docuHash(aliasedPath)}.json`);
304
+ // Note that metadataPath must be the same/in-sync as
305
+ // the path from createData for each MDX.
306
+ const aliasedPath = (0, utils_1.aliasedSitePath)(mdxPath, siteDir);
307
+ return path_1.default.join(dataDir, `${(0, utils_1.docuHash)(aliasedPath)}.json`);
316
308
  },
317
309
  // For blog posts a title in markdown is always removed
318
310
  // Blog posts title are rendered separately
319
311
  removeContentTitle: true,
312
+ // Assets allow to convert some relative images paths to require() calls
313
+ createAssets: ({ frontMatter, metadata, }) => ({
314
+ image: frontMatter.image,
315
+ authorsImageUrls: metadata.authors.map((author) => author.imageURL),
316
+ }),
320
317
  },
321
318
  },
322
319
  {
@@ -330,28 +327,24 @@ function pluginContentBlog(context, options) {
330
327
  };
331
328
  },
332
329
  async postBuild({ outDir }) {
333
- var _a;
334
- if (!((_a = options.feedOptions) === null || _a === void 0 ? void 0 : _a.type)) {
330
+ if (!options.feedOptions.type) {
335
331
  return;
336
332
  }
337
- const feed = await blogUtils_1.generateBlogFeed(contentPaths, context, options);
338
- if (!feed) {
333
+ // TODO: we shouldn't need to re-read the posts here!
334
+ // postBuild should receive loadedContent
335
+ const blogPosts = await (0, blogUtils_1.generateBlogPosts)(contentPaths, context, options);
336
+ if (!blogPosts.length) {
339
337
  return;
340
338
  }
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
- }));
339
+ await (0, feed_1.createBlogFeedFiles)({
340
+ blogPosts,
341
+ options,
342
+ outDir,
343
+ siteConfig,
344
+ });
352
345
  },
353
346
  injectHtmlTags({ content }) {
354
- var _a;
347
+ var _a, _b;
355
348
  if (!content.blogPosts.length) {
356
349
  return {};
357
350
  }
@@ -359,17 +352,17 @@ function pluginContentBlog(context, options) {
359
352
  return {};
360
353
  }
361
354
  const feedTypes = options.feedOptions.type;
362
- const { siteConfig: { title }, baseUrl, } = context;
355
+ const feedTitle = (_b = options.feedOptions.title) !== null && _b !== void 0 ? _b : context.siteConfig.title;
363
356
  const feedsConfig = {
364
357
  rss: {
365
358
  type: 'application/rss+xml',
366
359
  path: 'rss.xml',
367
- title: `${title} Blog RSS Feed`,
360
+ title: `${feedTitle} RSS Feed`,
368
361
  },
369
362
  atom: {
370
363
  type: 'application/atom+xml',
371
364
  path: 'atom.xml',
372
- title: `${title} Blog Atom Feed`,
365
+ title: `${feedTitle} Atom Feed`,
373
366
  },
374
367
  };
375
368
  const headTags = [];
@@ -384,7 +377,7 @@ function pluginContentBlog(context, options) {
384
377
  attributes: {
385
378
  rel: 'alternate',
386
379
  type,
387
- href: utils_1.normalizeUrl([
380
+ href: (0, utils_1.normalizeUrl)([
388
381
  baseUrl,
389
382
  options.routeBasePath,
390
383
  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 { BlogMarkdownLoaderOptions } from './types';
8
+ import type { LoaderContext } from 'webpack';
9
+ export default function markdownLoader(this: LoaderContext<BlogMarkdownLoaderOptions>, source: string): void;
@@ -8,24 +8,24 @@
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  const blogUtils_1 = require("./blogUtils");
10
10
  const loader_utils_1 = require("loader-utils");
11
- const markdownLoader = function (source) {
11
+ function markdownLoader(source) {
12
12
  const filePath = this.resourcePath;
13
13
  const fileString = source;
14
14
  const callback = this.async();
15
15
  const markdownLoaderOptions = this.getOptions();
16
16
  // Linkify blog posts
17
- let finalContent = blogUtils_1.linkify({
17
+ let finalContent = (0, blogUtils_1.linkify)({
18
18
  fileString,
19
19
  filePath,
20
20
  ...markdownLoaderOptions,
21
21
  });
22
22
  // Truncate content if requested (e.g: file.md?truncated=true).
23
23
  const truncated = this.resourceQuery
24
- ? !!loader_utils_1.parseQuery(this.resourceQuery).truncated
24
+ ? !!(0, loader_utils_1.parseQuery)(this.resourceQuery).truncated
25
25
  : undefined;
26
26
  if (truncated) {
27
- finalContent = blogUtils_1.truncate(finalContent, markdownLoaderOptions.truncateMarker);
27
+ finalContent = (0, blogUtils_1.truncate)(finalContent, markdownLoaderOptions.truncateMarker);
28
28
  }
29
29
  return callback && callback(null, finalContent);
30
- };
30
+ }
31
31
  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 { PluginOptions } from './types';
9
+ export declare const DEFAULT_OPTIONS: PluginOptions;
10
+ export declare const PluginOptionSchema: Joi.ObjectSchema<PluginOptions>;
@@ -8,8 +8,9 @@
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.PluginOptionSchema = exports.DEFAULT_OPTIONS = void 0;
10
10
  const utils_validation_1 = require("@docusaurus/utils-validation");
11
+ const utils_1 = require("@docusaurus/utils");
11
12
  exports.DEFAULT_OPTIONS = {
12
- feedOptions: { type: ['rss', 'atom'] },
13
+ feedOptions: { type: ['rss', 'atom'], copyright: '' },
13
14
  beforeDefaultRehypePlugins: [],
14
15
  beforeDefaultRemarkPlugins: [],
15
16
  admonitions: {},
@@ -26,21 +27,29 @@ exports.DEFAULT_OPTIONS = {
26
27
  blogSidebarCount: 5,
27
28
  blogSidebarTitle: 'Recent posts',
28
29
  postsPerPage: 10,
29
- include: ['*.md', '*.mdx'],
30
+ include: ['**/*.{md,mdx}'],
31
+ exclude: utils_1.GlobExcludeDefault,
30
32
  routeBasePath: 'blog',
33
+ tagsBasePath: 'tags',
34
+ archiveBasePath: 'archive',
31
35
  path: 'blog',
32
36
  editLocalizedFiles: false,
37
+ authorsMapPath: 'authors.yml',
38
+ readingTime: ({ content, defaultReadingTime }) => defaultReadingTime({ content }),
39
+ sortPosts: 'descending',
33
40
  };
34
41
  exports.PluginOptionSchema = utils_validation_1.Joi.object({
35
42
  path: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.path),
43
+ archiveBasePath: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.archiveBasePath),
36
44
  routeBasePath: utils_validation_1.Joi.string()
37
45
  // '' not allowed, see https://github.com/facebook/docusaurus/issues/3374
38
46
  // .allow('')
39
47
  .default(exports.DEFAULT_OPTIONS.routeBasePath),
48
+ tagsBasePath: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.tagsBasePath),
40
49
  include: utils_validation_1.Joi.array().items(utils_validation_1.Joi.string()).default(exports.DEFAULT_OPTIONS.include),
41
- postsPerPage: utils_validation_1.Joi.number()
42
- .integer()
43
- .min(1)
50
+ exclude: utils_validation_1.Joi.array().items(utils_validation_1.Joi.string()).default(exports.DEFAULT_OPTIONS.exclude),
51
+ postsPerPage: utils_validation_1.Joi.alternatives()
52
+ .try(utils_validation_1.Joi.equal('ALL').required(), utils_validation_1.Joi.number().integer().min(1).required())
44
53
  .default(exports.DEFAULT_OPTIONS.postsPerPage),
45
54
  blogListComponent: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.blogListComponent),
46
55
  blogPostComponent: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.blogPostComponent),
@@ -51,7 +60,7 @@ exports.PluginOptionSchema = utils_validation_1.Joi.object({
51
60
  .allow('')
52
61
  .default(exports.DEFAULT_OPTIONS.blogDescription),
53
62
  blogSidebarCount: utils_validation_1.Joi.alternatives()
54
- .try(utils_validation_1.Joi.equal('ALL').required(), utils_validation_1.Joi.number().required())
63
+ .try(utils_validation_1.Joi.equal('ALL').required(), utils_validation_1.Joi.number().integer().min(0).required())
55
64
  .default(exports.DEFAULT_OPTIONS.blogSidebarCount),
56
65
  blogSidebarTitle: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.blogSidebarTitle),
57
66
  showReadingTime: utils_validation_1.Joi.bool().default(exports.DEFAULT_OPTIONS.showReadingTime),
@@ -72,7 +81,19 @@ exports.PluginOptionSchema = utils_validation_1.Joi.object({
72
81
  .default(exports.DEFAULT_OPTIONS.feedOptions.type),
73
82
  title: utils_validation_1.Joi.string().allow(''),
74
83
  description: utils_validation_1.Joi.string().allow(''),
75
- copyright: utils_validation_1.Joi.string(),
84
+ // only add default value when user actually wants a feed (type is not null)
85
+ copyright: utils_validation_1.Joi.when('type', {
86
+ is: utils_validation_1.Joi.any().valid(null),
87
+ then: utils_validation_1.Joi.string().optional(),
88
+ otherwise: utils_validation_1.Joi.string()
89
+ .allow('')
90
+ .default(exports.DEFAULT_OPTIONS.feedOptions.copyright),
91
+ }),
76
92
  language: utils_validation_1.Joi.string(),
77
93
  }).default(exports.DEFAULT_OPTIONS.feedOptions),
94
+ authorsMapPath: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.authorsMapPath),
95
+ readingTime: utils_validation_1.Joi.function().default(() => exports.DEFAULT_OPTIONS.readingTime),
96
+ sortPosts: utils_validation_1.Joi.string()
97
+ .valid('descending', 'ascending')
98
+ .default(exports.DEFAULT_OPTIONS.sortPosts),
78
99
  });
@@ -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 { BlogContent, PluginOptions } from './types';
8
+ import type { TranslationFiles } from '@docusaurus/types';
9
+ export declare function getTranslationFiles(options: PluginOptions): TranslationFiles;
10
+ export declare function translateContent(content: BlogContent, translationFiles: TranslationFiles): BlogContent;
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) Facebook, Inc. and its affiliates.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.translateContent = exports.getTranslationFiles = void 0;
10
+ function translateListPage(blogListPaginated, translations) {
11
+ return blogListPaginated.map((page) => {
12
+ const { items, metadata } = page;
13
+ return {
14
+ items,
15
+ metadata: {
16
+ ...metadata,
17
+ blogTitle: translations.title.message,
18
+ blogDescription: translations.description.message,
19
+ },
20
+ };
21
+ });
22
+ }
23
+ function getTranslationFiles(options) {
24
+ return [
25
+ {
26
+ path: 'options',
27
+ content: {
28
+ title: {
29
+ message: options.blogTitle,
30
+ description: 'The title for the blog used in SEO',
31
+ },
32
+ description: {
33
+ message: options.blogDescription,
34
+ description: 'The description for the blog used in SEO',
35
+ },
36
+ 'sidebar.title': {
37
+ message: options.blogSidebarTitle,
38
+ description: 'The label for the left sidebar',
39
+ },
40
+ },
41
+ },
42
+ ];
43
+ }
44
+ exports.getTranslationFiles = getTranslationFiles;
45
+ function translateContent(content, translationFiles) {
46
+ const [{ content: optonsTranslations }] = translationFiles;
47
+ return {
48
+ ...content,
49
+ blogSidebarTitle: optonsTranslations['sidebar.title'].message,
50
+ blogListPaginated: translateListPage(content.blogListPaginated, optonsTranslations),
51
+ };
52
+ }
53
+ exports.translateContent = translateContent;