@docusaurus/plugin-content-blog 2.0.0-beta.16 → 2.0.0-beta.19

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.
package/src/index.ts CHANGED
@@ -7,6 +7,7 @@
7
7
 
8
8
  import path from 'path';
9
9
  import admonitions from 'remark-admonitions';
10
+ import footnoteIDFixer from './remark/footnoteIDFixer';
10
11
  import {
11
12
  normalizeUrl,
12
13
  docuHash,
@@ -19,29 +20,13 @@ import {
19
20
  getContentPathList,
20
21
  getDataFilePath,
21
22
  DEFAULT_PLUGIN_ID,
23
+ type TagsListItem,
24
+ type TagModule,
22
25
  } from '@docusaurus/utils';
23
26
  import {translateContent, getTranslationFiles} from './translations';
24
27
 
25
- import type {
26
- BlogTag,
27
- BlogTags,
28
- BlogContent,
29
- BlogItemsToMetadata,
30
- TagsModule,
31
- BlogPaginated,
32
- BlogContentPaths,
33
- BlogMarkdownLoaderOptions,
34
- MetaData,
35
- TagModule,
36
- } from './types';
37
- import {PluginOptionSchema} from './pluginOptionSchema';
38
- import type {
39
- LoadContext,
40
- Plugin,
41
- HtmlTags,
42
- OptionValidationContext,
43
- ValidationResult,
44
- } from '@docusaurus/types';
28
+ import type {BlogContentPaths, BlogMarkdownLoaderOptions} from './types';
29
+ import type {LoadContext, Plugin, HtmlTags} from '@docusaurus/types';
45
30
  import {
46
31
  generateBlogPosts,
47
32
  getSourceToPermalink,
@@ -52,7 +37,12 @@ import {createBlogFeedFiles} from './feed';
52
37
  import type {
53
38
  PluginOptions,
54
39
  BlogPostFrontMatter,
40
+ BlogPostMetadata,
55
41
  Assets,
42
+ BlogTag,
43
+ BlogTags,
44
+ BlogContent,
45
+ BlogPaginated,
56
46
  } from '@docusaurus/plugin-content-blog';
57
47
 
58
48
  export default async function pluginContentBlog(
@@ -111,7 +101,7 @@ export default async function pluginContentBlog(
111
101
  ) as string[];
112
102
  },
113
103
 
114
- async getTranslationFiles() {
104
+ getTranslationFiles() {
115
105
  return getTranslationFiles(options);
116
106
  },
117
107
 
@@ -126,6 +116,8 @@ export default async function pluginContentBlog(
126
116
  blogSidebarTitle,
127
117
  } = options;
128
118
 
119
+ const baseBlogUrl = normalizeUrl([baseUrl, routeBasePath]);
120
+ const blogTagsListPath = normalizeUrl([baseBlogUrl, tagsBasePath]);
129
121
  const blogPosts = await generateBlogPosts(contentPaths, context, options);
130
122
 
131
123
  if (!blogPosts.length) {
@@ -134,7 +126,7 @@ export default async function pluginContentBlog(
134
126
  blogPosts: [],
135
127
  blogListPaginated: [],
136
128
  blogTags: {},
137
- blogTagsListPath: null,
129
+ blogTagsListPath,
138
130
  blogTagsPaginated: [],
139
131
  };
140
132
  }
@@ -159,8 +151,6 @@ export default async function pluginContentBlog(
159
151
  }
160
152
  });
161
153
 
162
- const baseBlogUrl = normalizeUrl([baseUrl, routeBasePath]);
163
-
164
154
  const blogListPaginated: BlogPaginated[] = paginateBlogPosts({
165
155
  blogPosts,
166
156
  blogTitle,
@@ -176,11 +166,6 @@ export default async function pluginContentBlog(
176
166
  blogTitle,
177
167
  });
178
168
 
179
- const tagsPath = normalizeUrl([baseBlogUrl, tagsBasePath]);
180
-
181
- const blogTagsListPath =
182
- Object.keys(blogTags).length > 0 ? tagsPath : null;
183
-
184
169
  return {
185
170
  blogSidebarTitle,
186
171
  blogPosts,
@@ -214,20 +199,20 @@ export default async function pluginContentBlog(
214
199
  blogTagsListPath,
215
200
  } = blogContents;
216
201
 
217
- const blogItemsToMetadata: BlogItemsToMetadata = {};
202
+ const blogItemsToMetadata: {[postId: string]: BlogPostMetadata} = {};
218
203
 
219
204
  const sidebarBlogPosts =
220
205
  options.blogSidebarCount === 'ALL'
221
206
  ? blogPosts
222
207
  : blogPosts.slice(0, options.blogSidebarCount);
223
208
 
224
- if (archiveBasePath) {
209
+ if (archiveBasePath && blogPosts.length) {
225
210
  const archiveUrl = normalizeUrl([
226
211
  baseUrl,
227
212
  routeBasePath,
228
213
  archiveBasePath,
229
214
  ]);
230
- // creates a blog archive route
215
+ // Create a blog archive route
231
216
  const archiveProp = await createData(
232
217
  `${docuHash(archiveUrl)}.json`,
233
218
  JSON.stringify({blogPosts}, null, 2),
@@ -301,50 +286,62 @@ export default async function pluginContentBlog(
301
286
  exact: true,
302
287
  modules: {
303
288
  sidebar: aliasedSource(sidebarProp),
304
- items: items.map((postID) =>
305
- // To tell routes.js this is an import and not a nested object
306
- // to recurse.
307
- ({
308
- content: {
309
- __import: true,
310
- path: blogItemsToMetadata[postID].source,
311
- query: {
312
- truncated: true,
313
- },
289
+ items: items.map((postID) => ({
290
+ content: {
291
+ __import: true,
292
+ path: blogItemsToMetadata[postID]!.source,
293
+ query: {
294
+ truncated: true,
314
295
  },
315
- }),
316
- ),
296
+ },
297
+ })),
317
298
  metadata: aliasedSource(pageMetadataPath),
318
299
  },
319
300
  });
320
301
  }),
321
302
  );
322
303
 
323
- // Tags.
324
- if (blogTagsListPath === null) {
304
+ // Tags. This is the last part so we early-return if there are no tags.
305
+ if (Object.keys(blogTags).length === 0) {
325
306
  return;
326
307
  }
327
308
 
328
- const tagsModule: TagsModule = Object.fromEntries(
329
- Object.entries(blogTags).map(([tagKey, tag]) => {
330
- const tagModule: TagModule = {
331
- allTagsPath: blogTagsListPath,
332
- slug: tagKey,
333
- name: tag.name,
334
- count: tag.items.length,
335
- permalink: tag.permalink,
336
- };
337
- return [tag.name, tagModule];
338
- }),
339
- );
309
+ async function createTagsListPage() {
310
+ const tagsProp: TagsListItem[] = Object.values(blogTags).map((tag) => ({
311
+ label: tag.label,
312
+ permalink: tag.permalink,
313
+ count: tag.items.length,
314
+ }));
315
+
316
+ const tagsPropPath = await createData(
317
+ `${docuHash(`${blogTagsListPath}-tags`)}.json`,
318
+ JSON.stringify(tagsProp, null, 2),
319
+ );
340
320
 
341
- async function createTagRoutes(tag: BlogTag): Promise<void> {
321
+ addRoute({
322
+ path: blogTagsListPath,
323
+ component: blogTagsListComponent,
324
+ exact: true,
325
+ modules: {
326
+ sidebar: aliasedSource(sidebarProp),
327
+ tags: aliasedSource(tagsPropPath),
328
+ },
329
+ });
330
+ }
331
+
332
+ async function createTagPostsListPage(tag: BlogTag): Promise<void> {
342
333
  await Promise.all(
343
334
  tag.pages.map(async (blogPaginated) => {
344
335
  const {metadata, items} = blogPaginated;
345
- const tagsMetadataPath = await createData(
336
+ const tagProp: TagModule = {
337
+ label: tag.label,
338
+ permalink: tag.permalink,
339
+ allTagsPath: blogTagsListPath,
340
+ count: tag.items.length,
341
+ };
342
+ const tagPropPath = await createData(
346
343
  `${docuHash(metadata.permalink)}.json`,
347
- JSON.stringify(tagsModule[tag.name], null, 2),
344
+ JSON.stringify(tagProp, null, 2),
348
345
  );
349
346
 
350
347
  const listMetadataPath = await createData(
@@ -359,7 +356,7 @@ export default async function pluginContentBlog(
359
356
  modules: {
360
357
  sidebar: aliasedSource(sidebarProp),
361
358
  items: items.map((postID) => {
362
- const blogPostMetadata = blogItemsToMetadata[postID];
359
+ const blogPostMetadata = blogItemsToMetadata[postID]!;
363
360
  return {
364
361
  content: {
365
362
  __import: true,
@@ -370,7 +367,7 @@ export default async function pluginContentBlog(
370
367
  },
371
368
  };
372
369
  }),
373
- metadata: aliasedSource(tagsMetadataPath),
370
+ tag: aliasedSource(tagPropPath),
374
371
  listMetadata: aliasedSource(listMetadataPath),
375
372
  },
376
373
  });
@@ -378,25 +375,8 @@ export default async function pluginContentBlog(
378
375
  );
379
376
  }
380
377
 
381
- await Promise.all(Object.values(blogTags).map(createTagRoutes));
382
-
383
- // Only create /tags page if there are tags.
384
- if (Object.keys(blogTags).length > 0) {
385
- const tagsListPath = await createData(
386
- `${docuHash(`${blogTagsListPath}-tags`)}.json`,
387
- JSON.stringify(tagsModule, null, 2),
388
- );
389
-
390
- addRoute({
391
- path: blogTagsListPath,
392
- component: blogTagsListComponent,
393
- exact: true,
394
- modules: {
395
- sidebar: aliasedSource(sidebarProp),
396
- tags: aliasedSource(tagsListPath),
397
- },
398
- });
399
- }
378
+ await createTagsListPage();
379
+ await Promise.all(Object.values(blogTags).map(createTagPostsListPage));
400
380
  },
401
381
 
402
382
  translateContent({content, translationFiles}) {
@@ -449,7 +429,10 @@ export default async function pluginContentBlog(
449
429
  options: {
450
430
  remarkPlugins,
451
431
  rehypePlugins,
452
- beforeDefaultRemarkPlugins,
432
+ beforeDefaultRemarkPlugins: [
433
+ footnoteIDFixer,
434
+ ...beforeDefaultRemarkPlugins,
435
+ ],
453
436
  beforeDefaultRehypePlugins,
454
437
  staticDirs: siteConfig.staticDirectories.map((dir) =>
455
438
  path.resolve(siteDir, dir),
@@ -479,7 +462,7 @@ export default async function pluginContentBlog(
479
462
  metadata,
480
463
  }: {
481
464
  frontMatter: BlogPostFrontMatter;
482
- metadata: MetaData;
465
+ metadata: BlogPostMetadata;
483
466
  }): Assets => ({
484
467
  image: frontMatter.image,
485
468
  authorsImageUrls: metadata.authors.map(
@@ -512,6 +495,7 @@ export default async function pluginContentBlog(
512
495
  options,
513
496
  outDir,
514
497
  siteConfig,
498
+ locale: currentLocale,
515
499
  });
516
500
  },
517
501
 
@@ -546,13 +530,11 @@ export default async function pluginContentBlog(
546
530
  const headTags: HtmlTags = [];
547
531
 
548
532
  feedTypes.forEach((feedType) => {
549
- const feedConfig = feedsConfig[feedType] || {};
550
-
551
- if (!feedsConfig) {
552
- return;
553
- }
554
-
555
- const {type, path: feedConfigPath, title: feedConfigTitle} = feedConfig;
533
+ const {
534
+ type,
535
+ path: feedConfigPath,
536
+ title: feedConfigTitle,
537
+ } = feedsConfig[feedType];
556
538
 
557
539
  headTags.push({
558
540
  tagName: 'link',
@@ -576,10 +558,4 @@ export default async function pluginContentBlog(
576
558
  };
577
559
  }
578
560
 
579
- export function validateOptions({
580
- validate,
581
- options,
582
- }: OptionValidationContext<PluginOptions>): ValidationResult<PluginOptions> {
583
- const validatedOptions = validate(PluginOptionSchema, options);
584
- return validatedOptions;
585
- }
561
+ export {validateOptions} from './options';
@@ -34,5 +34,5 @@ export default function markdownLoader(
34
34
  finalContent = truncate(finalContent, markdownLoaderOptions.truncateMarker);
35
35
  }
36
36
 
37
- return callback && callback(null, finalContent);
37
+ return callback?.(null, finalContent);
38
38
  }
@@ -13,7 +13,8 @@ import {
13
13
  URISchema,
14
14
  } from '@docusaurus/utils-validation';
15
15
  import {GlobExcludeDefault} from '@docusaurus/utils';
16
- import type {PluginOptions} from '@docusaurus/plugin-content-blog';
16
+ import type {PluginOptions, Options} from '@docusaurus/plugin-content-blog';
17
+ import type {OptionValidationContext} from '@docusaurus/types';
17
18
 
18
19
  export const DEFAULT_OPTIONS: PluginOptions = {
19
20
  feedOptions: {type: ['rss', 'atom'], copyright: ''},
@@ -46,7 +47,7 @@ export const DEFAULT_OPTIONS: PluginOptions = {
46
47
  sortPosts: 'descending',
47
48
  };
48
49
 
49
- export const PluginOptionSchema = Joi.object<PluginOptions>({
50
+ const PluginOptionSchema = Joi.object<PluginOptions>({
50
51
  path: Joi.string().default(DEFAULT_OPTIONS.path),
51
52
  archiveBasePath: Joi.string()
52
53
  .default(DEFAULT_OPTIONS.archiveBasePath)
@@ -110,7 +111,7 @@ export const PluginOptionSchema = Joi.object<PluginOptions>({
110
111
  .default(DEFAULT_OPTIONS.feedOptions.type),
111
112
  title: Joi.string().allow(''),
112
113
  description: Joi.string().allow(''),
113
- // only add default value when user actually wants a feed (type is not null)
114
+ // Only add default value when user actually wants a feed (type is not null)
114
115
  copyright: Joi.when('type', {
115
116
  is: Joi.any().valid(null),
116
117
  then: Joi.string().optional(),
@@ -125,4 +126,15 @@ export const PluginOptionSchema = Joi.object<PluginOptions>({
125
126
  sortPosts: Joi.string()
126
127
  .valid('descending', 'ascending')
127
128
  .default(DEFAULT_OPTIONS.sortPosts),
128
- });
129
+ }).default(DEFAULT_OPTIONS);
130
+
131
+ export function validateOptions({
132
+ validate,
133
+ options,
134
+ }: OptionValidationContext<Options, PluginOptions>): PluginOptions {
135
+ const validatedOptions = validate(
136
+ PluginOptionSchema,
137
+ options,
138
+ ) as PluginOptions;
139
+ return validatedOptions;
140
+ }