@docusaurus/plugin-content-blog 2.0.0-beta.8bda3b2db → 2.0.0-beta.9

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