@docusaurus/plugin-content-blog 2.0.0-beta.1 → 2.0.0-beta.10

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 (66) 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 +35 -23
  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.d.ts +1 -1
  11. package/lib/index.js +109 -112
  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 +28 -7
  16. package/lib/translations.d.ts +10 -0
  17. package/lib/translations.js +53 -0
  18. package/lib/types.d.ts +54 -14
  19. package/package.json +19 -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 +165 -36
  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 +84 -12
  53. package/src/__tests__/pluginOptionSchema.test.ts +3 -3
  54. package/src/__tests__/translations.test.ts +92 -0
  55. package/src/authors.ts +198 -0
  56. package/src/blogFrontMatter.ts +76 -37
  57. package/src/blogUtils.ts +202 -179
  58. package/{types.d.ts → src/deps.d.ts} +0 -0
  59. package/src/feed.ts +129 -0
  60. package/src/index.ts +131 -112
  61. package/src/markdownLoader.ts +8 -12
  62. package/{index.d.ts → src/plugin-content-blog.d.ts} +35 -31
  63. package/src/pluginOptionSchema.ts +31 -9
  64. package/src/translations.ts +63 -0
  65. package/src/types.ts +69 -16
  66. package/src/__tests__/__snapshots__/generateBlogFeed.test.ts.snap +0 -76
package/src/index.ts CHANGED
@@ -5,7 +5,6 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- import fs from 'fs-extra';
9
8
  import path from 'path';
10
9
  import admonitions from 'remark-admonitions';
11
10
  import {
@@ -16,12 +15,10 @@ import {
16
15
  reportMessage,
17
16
  posixPath,
18
17
  addTrailingPathSeparator,
19
- } from '@docusaurus/utils';
20
- import {
21
- STATIC_DIR_NAME,
18
+ createAbsoluteFilePathMatcher,
22
19
  DEFAULT_PLUGIN_ID,
23
- } from '@docusaurus/core/lib/constants';
24
- import {flatten, take, kebabCase} from 'lodash';
20
+ } from '@docusaurus/utils';
21
+ import {translateContent, getTranslationFiles} from './translations';
25
22
 
26
23
  import {
27
24
  PluginOptions,
@@ -30,9 +27,10 @@ import {
30
27
  BlogItemsToMetadata,
31
28
  TagsModule,
32
29
  BlogPaginated,
33
- BlogPost,
34
30
  BlogContentPaths,
35
31
  BlogMarkdownLoaderOptions,
32
+ MetaData,
33
+ Assets,
36
34
  } from './types';
37
35
  import {PluginOptionSchema} from './pluginOptionSchema';
38
36
  import {
@@ -46,16 +44,18 @@ import {
46
44
  } from '@docusaurus/types';
47
45
  import {Configuration} from 'webpack';
48
46
  import {
49
- generateBlogFeed,
50
47
  generateBlogPosts,
51
48
  getContentPathList,
52
49
  getSourceToPermalink,
50
+ getBlogTags,
53
51
  } from './blogUtils';
52
+ import {BlogPostFrontMatter} from './blogFrontMatter';
53
+ import {createBlogFeedFiles} from './feed';
54
54
 
55
55
  export default function pluginContentBlog(
56
56
  context: LoadContext,
57
57
  options: PluginOptions,
58
- ): Plugin<BlogContent | null> {
58
+ ): Plugin<BlogContent> {
59
59
  if (options.admonitions) {
60
60
  options.remarkPlugins = options.remarkPlugins.concat([
61
61
  [admonitions, options.admonitions],
@@ -64,10 +64,11 @@ export default function pluginContentBlog(
64
64
 
65
65
  const {
66
66
  siteDir,
67
- siteConfig: {onBrokenMarkdownLinks},
67
+ siteConfig,
68
68
  generatedFilesDir,
69
69
  i18n: {currentLocale},
70
70
  } = context;
71
+ const {onBrokenMarkdownLinks, baseUrl} = siteConfig;
71
72
 
72
73
  const contentPaths: BlogContentPaths = {
73
74
  contentPath: path.resolve(siteDir, options.path),
@@ -88,38 +89,51 @@ export default function pluginContentBlog(
88
89
  const aliasedSource = (source: string) =>
89
90
  `~blog/${posixPath(path.relative(pluginDataDirRoot, source))}`;
90
91
 
91
- let blogPosts: BlogPost[] = [];
92
-
93
92
  return {
94
93
  name: 'docusaurus-plugin-content-blog',
95
94
 
96
95
  getPathsToWatch() {
97
- const {include = []} = options;
98
- return flatten(
99
- getContentPathList(contentPaths).map((contentPath) => {
100
- return include.map((pattern) => `${contentPath}/${pattern}`);
101
- }),
96
+ const {include, authorsMapPath} = options;
97
+ const contentMarkdownGlobs = getContentPathList(contentPaths).flatMap(
98
+ (contentPath) => include.map((pattern) => `${contentPath}/${pattern}`),
102
99
  );
103
- },
104
100
 
105
- getClientModules() {
106
- const modules = [];
101
+ // TODO: we should read this path in plugin! but plugins do not support async init for now :'(
102
+ // const authorsMapFilePath = await getAuthorsMapFilePath({authorsMapPath,contentPaths,});
103
+ // simplified impl, better than nothing for now:
104
+ const authorsMapFilePath = path.join(
105
+ contentPaths.contentPath,
106
+ authorsMapPath,
107
+ );
107
108
 
108
- if (options.admonitions) {
109
- modules.push(require.resolve('remark-admonitions/styles/infima.css'));
110
- }
109
+ return [authorsMapFilePath, ...contentMarkdownGlobs];
110
+ },
111
111
 
112
- return modules;
112
+ async getTranslationFiles() {
113
+ return getTranslationFiles(options);
113
114
  },
114
115
 
115
116
  // Fetches blog contents and returns metadata for the necessary routes.
116
117
  async loadContent() {
117
- const {postsPerPage, routeBasePath} = options;
118
+ const {
119
+ postsPerPage: postsPerPageOption,
120
+ routeBasePath,
121
+ tagsBasePath,
122
+ blogDescription,
123
+ blogTitle,
124
+ blogSidebarTitle,
125
+ } = options;
118
126
 
119
- blogPosts = await generateBlogPosts(contentPaths, context, options);
127
+ const blogPosts = await generateBlogPosts(contentPaths, context, options);
120
128
 
121
129
  if (!blogPosts.length) {
122
- return null;
130
+ return {
131
+ blogSidebarTitle,
132
+ blogPosts: [],
133
+ blogListPaginated: [],
134
+ blogTags: {},
135
+ blogTagsListPath: null,
136
+ };
123
137
  }
124
138
 
125
139
  // Colocate next and prev metadata.
@@ -145,18 +159,17 @@ export default function pluginContentBlog(
145
159
  // Blog pagination routes.
146
160
  // Example: `/blog`, `/blog/page/1`, `/blog/page/2`
147
161
  const totalCount = blogPosts.length;
162
+ const postsPerPage =
163
+ postsPerPageOption === 'ALL' ? totalCount : postsPerPageOption;
148
164
  const numberOfPages = Math.ceil(totalCount / postsPerPage);
149
- const {
150
- siteConfig: {baseUrl = ''},
151
- } = context;
152
- const basePageUrl = normalizeUrl([baseUrl, routeBasePath]);
165
+ const baseBlogUrl = normalizeUrl([baseUrl, routeBasePath]);
153
166
 
154
167
  const blogListPaginated: BlogPaginated[] = [];
155
168
 
156
169
  function blogPaginationPermalink(page: number) {
157
170
  return page > 0
158
- ? normalizeUrl([basePageUrl, `page/${page + 1}`])
159
- : basePageUrl;
171
+ ? normalizeUrl([baseBlogUrl, `page/${page + 1}`])
172
+ : baseBlogUrl;
160
173
  }
161
174
 
162
175
  for (let page = 0; page < numberOfPages; page += 1) {
@@ -172,8 +185,8 @@ export default function pluginContentBlog(
172
185
  page < numberOfPages - 1
173
186
  ? blogPaginationPermalink(page + 1)
174
187
  : null,
175
- blogDescription: options.blogDescription,
176
- blogTitle: options.blogTitle,
188
+ blogDescription,
189
+ blogTitle,
177
190
  },
178
191
  items: blogPosts
179
192
  .slice(page * postsPerPage, (page + 1) * postsPerPage)
@@ -181,46 +194,15 @@ export default function pluginContentBlog(
181
194
  });
182
195
  }
183
196
 
184
- const blogTags: BlogTags = {};
185
- const tagsPath = normalizeUrl([basePageUrl, 'tags']);
186
- blogPosts.forEach((blogPost) => {
187
- const {tags} = blogPost.metadata;
188
- if (!tags || tags.length === 0) {
189
- // TODO: Extract tags out into a separate plugin.
190
- // eslint-disable-next-line no-param-reassign
191
- blogPost.metadata.tags = [];
192
- return;
193
- }
197
+ const blogTags: BlogTags = getBlogTags(blogPosts);
194
198
 
195
- // eslint-disable-next-line no-param-reassign
196
- blogPost.metadata.tags = tags.map((tag) => {
197
- if (typeof tag === 'string') {
198
- const normalizedTag = kebabCase(tag);
199
- const permalink = normalizeUrl([tagsPath, normalizedTag]);
200
- if (!blogTags[normalizedTag]) {
201
- blogTags[normalizedTag] = {
202
- // Will only use the name of the first occurrence of the tag.
203
- name: tag.toLowerCase(),
204
- items: [],
205
- permalink,
206
- };
207
- }
208
-
209
- blogTags[normalizedTag].items.push(blogPost.id);
210
-
211
- return {
212
- label: tag,
213
- permalink,
214
- };
215
- }
216
- return tag;
217
- });
218
- });
199
+ const tagsPath = normalizeUrl([baseBlogUrl, tagsBasePath]);
219
200
 
220
201
  const blogTagsListPath =
221
202
  Object.keys(blogTags).length > 0 ? tagsPath : null;
222
203
 
223
204
  return {
205
+ blogSidebarTitle,
224
206
  blogPosts,
225
207
  blogListPaginated,
226
208
  blogTags,
@@ -238,11 +220,14 @@ export default function pluginContentBlog(
238
220
  blogPostComponent,
239
221
  blogTagsListComponent,
240
222
  blogTagsPostsComponent,
223
+ routeBasePath,
224
+ archiveBasePath,
241
225
  } = options;
242
226
 
243
227
  const {addRoute, createData} = actions;
244
228
  const {
245
- blogPosts: loadedBlogPosts,
229
+ blogSidebarTitle,
230
+ blogPosts,
246
231
  blogListPaginated,
247
232
  blogTags,
248
233
  blogTagsListPath,
@@ -253,7 +238,27 @@ export default function pluginContentBlog(
253
238
  const sidebarBlogPosts =
254
239
  options.blogSidebarCount === 'ALL'
255
240
  ? blogPosts
256
- : take(blogPosts, options.blogSidebarCount);
241
+ : blogPosts.slice(0, options.blogSidebarCount);
242
+
243
+ const archiveUrl = normalizeUrl([
244
+ baseUrl,
245
+ routeBasePath,
246
+ archiveBasePath,
247
+ ]);
248
+
249
+ // creates a blog archive route
250
+ const archiveProp = await createData(
251
+ `${docuHash(archiveUrl)}.json`,
252
+ JSON.stringify({blogPosts}, null, 2),
253
+ );
254
+ addRoute({
255
+ path: archiveUrl,
256
+ component: '@theme/BlogArchivePage',
257
+ exact: true,
258
+ modules: {
259
+ archive: aliasedSource(archiveProp),
260
+ },
261
+ });
257
262
 
258
263
  // This prop is useful to provide the blog list sidebar
259
264
  const sidebarProp = await createData(
@@ -262,7 +267,7 @@ export default function pluginContentBlog(
262
267
  `blog-post-list-prop-${pluginId}.json`,
263
268
  JSON.stringify(
264
269
  {
265
- title: options.blogSidebarTitle,
270
+ title: blogSidebarTitle,
266
271
  items: sidebarBlogPosts.map((blogPost) => ({
267
272
  title: blogPost.metadata.title,
268
273
  permalink: blogPost.metadata.permalink,
@@ -275,7 +280,7 @@ export default function pluginContentBlog(
275
280
 
276
281
  // Create routes for blog entries.
277
282
  await Promise.all(
278
- loadedBlogPosts.map(async (blogPost) => {
283
+ blogPosts.map(async (blogPost) => {
279
284
  const {id, metadata} = blogPost;
280
285
  await createData(
281
286
  // Note that this created data path must be in sync with
@@ -314,9 +319,9 @@ export default function pluginContentBlog(
314
319
  exact: true,
315
320
  modules: {
316
321
  sidebar: aliasedSource(sidebarProp),
317
- items: items.map((postID) => {
322
+ items: items.map((postID) =>
318
323
  // To tell routes.js this is an import and not a nested object to recurse.
319
- return {
324
+ ({
320
325
  content: {
321
326
  __import: true,
322
327
  path: blogItemsToMetadata[postID].source,
@@ -324,8 +329,8 @@ export default function pluginContentBlog(
324
329
  truncated: true,
325
330
  },
326
331
  },
327
- };
328
- }),
332
+ }),
333
+ ),
329
334
  metadata: aliasedSource(pageMetadataPath),
330
335
  },
331
336
  });
@@ -343,6 +348,7 @@ export default function pluginContentBlog(
343
348
  Object.keys(blogTags).map(async (tag) => {
344
349
  const {name, items, permalink} = blogTags[tag];
345
350
 
351
+ // Refactor all this, see docs implementation
346
352
  tagsModule[tag] = {
347
353
  allTagsPath: blogTagsListPath,
348
354
  slug: tag,
@@ -399,10 +405,15 @@ export default function pluginContentBlog(
399
405
  }
400
406
  },
401
407
 
408
+ translateContent({content, translationFiles}) {
409
+ return translateContent(content, translationFiles);
410
+ },
411
+
402
412
  configureWebpack(
403
413
  _config: Configuration,
404
414
  isServer: boolean,
405
415
  {getJSLoader}: ConfigureWebpackUtils,
416
+ content,
406
417
  ) {
407
418
  const {
408
419
  rehypePlugins,
@@ -416,7 +427,7 @@ export default function pluginContentBlog(
416
427
  siteDir,
417
428
  contentPaths,
418
429
  truncateMarker,
419
- sourceToPermalink: getSourceToPermalink(blogPosts),
430
+ sourceToPermalink: getSourceToPermalink(content.blogPosts),
420
431
  onBrokenMarkdownLink: (brokenMarkdownLink) => {
421
432
  if (onBrokenMarkdownLinks === 'ignore') {
422
433
  return;
@@ -428,6 +439,7 @@ export default function pluginContentBlog(
428
439
  },
429
440
  };
430
441
 
442
+ const contentDirs = getContentPathList(contentPaths);
431
443
  return {
432
444
  resolve: {
433
445
  alias: {
@@ -438,7 +450,7 @@ export default function pluginContentBlog(
438
450
  rules: [
439
451
  {
440
452
  test: /(\.mdx?)$/,
441
- include: getContentPathList(contentPaths)
453
+ include: contentDirs
442
454
  // Trailing slash is important, see https://github.com/facebook/docusaurus/pull/3970
443
455
  .map(addTrailingPathSeparator),
444
456
  use: [
@@ -450,10 +462,17 @@ export default function pluginContentBlog(
450
462
  rehypePlugins,
451
463
  beforeDefaultRemarkPlugins,
452
464
  beforeDefaultRehypePlugins,
453
- staticDir: path.join(siteDir, STATIC_DIR_NAME),
454
- // Note that metadataPath must be the same/in-sync as
455
- // the path from createData for each MDX.
465
+ staticDirs: siteConfig.staticDirectories.map((dir) =>
466
+ path.resolve(siteDir, dir),
467
+ ),
468
+ siteDir,
469
+ isMDXPartial: createAbsoluteFilePathMatcher(
470
+ options.exclude,
471
+ contentDirs,
472
+ ),
456
473
  metadataPath: (mdxPath: string) => {
474
+ // Note that metadataPath must be the same/in-sync as
475
+ // the path from createData for each MDX.
457
476
  const aliasedPath = aliasedSitePath(mdxPath, siteDir);
458
477
  return path.join(
459
478
  dataDir,
@@ -463,6 +482,20 @@ export default function pluginContentBlog(
463
482
  // For blog posts a title in markdown is always removed
464
483
  // Blog posts title are rendered separately
465
484
  removeContentTitle: true,
485
+
486
+ // Assets allow to convert some relative images paths to require() calls
487
+ createAssets: ({
488
+ frontMatter,
489
+ metadata,
490
+ }: {
491
+ frontMatter: BlogPostFrontMatter;
492
+ metadata: MetaData;
493
+ }): Assets => ({
494
+ image: frontMatter.image,
495
+ authorsImageUrls: metadata.authors.map(
496
+ (author) => author.imageURL,
497
+ ),
498
+ }),
466
499
  },
467
500
  },
468
501
  {
@@ -477,37 +510,26 @@ export default function pluginContentBlog(
477
510
  },
478
511
 
479
512
  async postBuild({outDir}: Props) {
480
- if (!options.feedOptions?.type) {
513
+ if (!options.feedOptions.type) {
481
514
  return;
482
515
  }
483
516
 
484
- const feed = await generateBlogFeed(contentPaths, context, options);
485
-
486
- if (!feed) {
517
+ // TODO: we shouldn't need to re-read the posts here!
518
+ // postBuild should receive loadedContent
519
+ const blogPosts = await generateBlogPosts(contentPaths, context, options);
520
+ if (!blogPosts.length) {
487
521
  return;
488
522
  }
489
-
490
- const feedTypes = options.feedOptions.type;
491
-
492
- await Promise.all(
493
- feedTypes.map(async (feedType) => {
494
- const feedPath = path.join(
495
- outDir,
496
- options.routeBasePath,
497
- `${feedType}.xml`,
498
- );
499
- const feedContent = feedType === 'rss' ? feed.rss2() : feed.atom1();
500
- try {
501
- await fs.outputFile(feedPath, feedContent);
502
- } catch (err) {
503
- throw new Error(`Generating ${feedType} feed failed: ${err}.`);
504
- }
505
- }),
506
- );
523
+ await createBlogFeedFiles({
524
+ blogPosts,
525
+ options,
526
+ outDir,
527
+ siteConfig,
528
+ });
507
529
  },
508
530
 
509
- injectHtmlTags() {
510
- if (!blogPosts.length) {
531
+ injectHtmlTags({content}) {
532
+ if (!content.blogPosts.length) {
511
533
  return {};
512
534
  }
513
535
 
@@ -516,20 +538,17 @@ export default function pluginContentBlog(
516
538
  }
517
539
 
518
540
  const feedTypes = options.feedOptions.type;
519
- const {
520
- siteConfig: {title},
521
- baseUrl,
522
- } = context;
541
+ const feedTitle = options.feedOptions.title ?? context.siteConfig.title;
523
542
  const feedsConfig = {
524
543
  rss: {
525
544
  type: 'application/rss+xml',
526
545
  path: 'rss.xml',
527
- title: `${title} Blog RSS Feed`,
546
+ title: `${feedTitle} RSS Feed`,
528
547
  },
529
548
  atom: {
530
549
  type: 'application/atom+xml',
531
550
  path: 'atom.xml',
532
- title: `${title} Blog Atom Feed`,
551
+ title: `${feedTitle} Atom Feed`,
533
552
  },
534
553
  };
535
554
  const headTags: HtmlTags = [];
@@ -8,18 +8,16 @@
8
8
  import {truncate, linkify} from './blogUtils';
9
9
  import {parseQuery} from 'loader-utils';
10
10
  import {BlogMarkdownLoaderOptions} from './types';
11
+ import type {LoaderContext} from 'webpack';
11
12
 
12
- // TODO temporary until Webpack5 export this type
13
- // see https://github.com/webpack/webpack/issues/11630
14
- interface Loader extends Function {
15
- (this: any, source: string): string | Buffer | void | undefined;
16
- }
17
-
18
- const markdownLoader: Loader = function (source) {
13
+ export default function markdownLoader(
14
+ this: LoaderContext<BlogMarkdownLoaderOptions>,
15
+ source: string,
16
+ ): void {
19
17
  const filePath = this.resourcePath;
20
- const fileString = source as string;
18
+ const fileString = source;
21
19
  const callback = this.async();
22
- const markdownLoaderOptions = this.getOptions() as BlogMarkdownLoaderOptions;
20
+ const markdownLoaderOptions = this.getOptions();
23
21
 
24
22
  // Linkify blog posts
25
23
  let finalContent = linkify({
@@ -38,6 +36,4 @@ const markdownLoader: Loader = function (source) {
38
36
  }
39
37
 
40
38
  return callback && callback(null, finalContent);
41
- };
42
-
43
- export default markdownLoader;
39
+ }
@@ -5,8 +5,9 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- /* eslint-disable import/no-duplicates */
9
- /* eslint-disable camelcase */
8
+ declare module '@docusaurus/plugin-content-blog' {
9
+ export type Options = Partial<import('./types').UserPluginOptions>;
10
+ }
10
11
 
11
12
  declare module '@theme/BlogSidebar' {
12
13
  export type BlogSidebarItem = {title: string; permalink: string};
@@ -15,32 +16,20 @@ declare module '@theme/BlogSidebar' {
15
16
  items: BlogSidebarItem[];
16
17
  };
17
18
 
18
- export type Props = {
19
+ export interface Props {
19
20
  readonly sidebar: BlogSidebar;
20
- };
21
+ }
21
22
 
22
23
  const BlogSidebar: (props: Props) => JSX.Element;
23
24
  export default BlogSidebar;
24
25
  }
25
26
 
26
27
  declare module '@theme/BlogPostPage' {
27
- import type {TOCItem} from '@docusaurus/types';
28
28
  import type {BlogSidebar} from '@theme/BlogSidebar';
29
+ import type {TOCItem} from '@docusaurus/types';
29
30
 
30
- export type FrontMatter = {
31
- readonly title: string;
32
- readonly author?: string;
33
- readonly image?: string;
34
- readonly tags?: readonly string[];
35
- readonly keywords?: readonly string[];
36
- readonly author_url?: string;
37
- readonly authorURL?: string;
38
- readonly author_title?: string;
39
- readonly authorTitle?: string;
40
- readonly author_image_url?: string;
41
- readonly authorImageURL?: string;
42
- readonly hide_table_of_contents?: boolean;
43
- };
31
+ export type FrontMatter = import('./blogFrontMatter').BlogPostFrontMatter;
32
+ export type Assets = import('./types').Assets;
44
33
 
45
34
  export type Metadata = {
46
35
  readonly title: string;
@@ -53,6 +42,7 @@ declare module '@theme/BlogPostPage' {
53
42
  readonly truncated?: string;
54
43
  readonly nextItem?: {readonly title: string; readonly permalink: string};
55
44
  readonly prevItem?: {readonly title: string; readonly permalink: string};
45
+ readonly authors: import('./types').Author[];
56
46
  readonly tags: readonly {
57
47
  readonly label: string;
58
48
  readonly permalink: string;
@@ -61,15 +51,16 @@ declare module '@theme/BlogPostPage' {
61
51
 
62
52
  export type Content = {
63
53
  readonly frontMatter: FrontMatter;
54
+ readonly assets: Assets;
64
55
  readonly metadata: Metadata;
65
56
  readonly toc: readonly TOCItem[];
66
57
  (): JSX.Element;
67
58
  };
68
59
 
69
- export type Props = {
60
+ export interface Props {
70
61
  readonly sidebar: BlogSidebar;
71
62
  readonly content: Content;
72
- };
63
+ }
73
64
 
74
65
  const BlogPostPage: (props: Props) => JSX.Element;
75
66
  export default BlogPostPage;
@@ -79,10 +70,6 @@ declare module '@theme/BlogListPage' {
79
70
  import type {Content} from '@theme/BlogPostPage';
80
71
  import type {BlogSidebar} from '@theme/BlogSidebar';
81
72
 
82
- export type Item = {
83
- readonly content: () => JSX.Element;
84
- };
85
-
86
73
  export type Metadata = {
87
74
  readonly blogTitle: string;
88
75
  readonly blogDescription: string;
@@ -95,11 +82,11 @@ declare module '@theme/BlogListPage' {
95
82
  readonly totalPages: number;
96
83
  };
97
84
 
98
- export type Props = {
85
+ export interface Props {
99
86
  readonly sidebar: BlogSidebar;
100
87
  readonly metadata: Metadata;
101
88
  readonly items: readonly {readonly content: Content}[];
102
- };
89
+ }
103
90
 
104
91
  const BlogListPage: (props: Props) => JSX.Element;
105
92
  export default BlogListPage;
@@ -116,10 +103,10 @@ declare module '@theme/BlogTagsListPage' {
116
103
  slug: string;
117
104
  };
118
105
 
119
- export type Props = {
106
+ export interface Props {
120
107
  readonly sidebar: BlogSidebar;
121
108
  readonly tags: Readonly<Record<string, Tag>>;
122
- };
109
+ }
123
110
 
124
111
  const BlogTagsListPage: (props: Props) => JSX.Element;
125
112
  export default BlogTagsListPage;
@@ -130,9 +117,26 @@ declare module '@theme/BlogTagsPostsPage' {
130
117
  import type {Tag} from '@theme/BlogTagsListPage';
131
118
  import type {Content} from '@theme/BlogPostPage';
132
119
 
133
- export type Props = {
120
+ export interface Props {
134
121
  readonly sidebar: BlogSidebar;
135
122
  readonly metadata: Tag;
136
123
  readonly items: readonly {readonly content: Content}[];
137
- };
124
+ }
125
+
126
+ const BlogTagsPostsPage: (props: Props) => JSX.Element;
127
+ export default BlogTagsPostsPage;
128
+ }
129
+
130
+ declare module '@theme/BlogArchivePage' {
131
+ import type {Content} from '@theme/BlogPostPage';
132
+
133
+ export type ArchiveBlogPost = Content;
134
+
135
+ export interface Props {
136
+ readonly archive: {
137
+ readonly blogPosts: readonly ArchiveBlogPost[];
138
+ };
139
+ }
140
+
141
+ export default function BlogArchivePage(props: Props): JSX.Element;
138
142
  }