@docusaurus/plugin-content-blog 0.0.0-5983 → 0.0.0-5987

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.
@@ -0,0 +1,21 @@
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 { Author, PluginOptions } from '@docusaurus/plugin-content-blog';
8
+ export declare function reportAuthorsProblems(params: {
9
+ authors: Author[];
10
+ blogSourceRelative: string;
11
+ options: Pick<PluginOptions, 'onInlineAuthors' | 'authorsMapPath'>;
12
+ }): void;
13
+ export declare function reportInlineAuthors({ authors, blogSourceRelative, options: { onInlineAuthors, authorsMapPath }, }: {
14
+ authors: Author[];
15
+ blogSourceRelative: string;
16
+ options: Pick<PluginOptions, 'onInlineAuthors' | 'authorsMapPath'>;
17
+ }): void;
18
+ export declare function reportDuplicateAuthors({ authors, blogSourceRelative, }: {
19
+ authors: Author[];
20
+ blogSourceRelative: string;
21
+ }): void;
@@ -0,0 +1,51 @@
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.reportAuthorsProblems = reportAuthorsProblems;
10
+ exports.reportInlineAuthors = reportInlineAuthors;
11
+ exports.reportDuplicateAuthors = reportDuplicateAuthors;
12
+ const tslib_1 = require("tslib");
13
+ const lodash_1 = tslib_1.__importDefault(require("lodash"));
14
+ const logger_1 = tslib_1.__importDefault(require("@docusaurus/logger"));
15
+ function reportAuthorsProblems(params) {
16
+ reportInlineAuthors(params);
17
+ reportDuplicateAuthors(params);
18
+ }
19
+ function reportInlineAuthors({ authors, blogSourceRelative, options: { onInlineAuthors, authorsMapPath }, }) {
20
+ if (onInlineAuthors === 'ignore') {
21
+ return;
22
+ }
23
+ const inlineAuthors = authors.filter((author) => !author.key);
24
+ if (inlineAuthors.length > 0) {
25
+ logger_1.default.report(onInlineAuthors)(logger_1.default.interpolate `Some blog authors used in path=${blogSourceRelative} are not defined in path=${authorsMapPath}:
26
+ - ${inlineAuthors.map(authorToString).join('\n- ')}
27
+
28
+ Note that we recommend to declare authors once in a path=${authorsMapPath} file and reference them by key in blog posts front matter to avoid author info duplication.
29
+ But if you want to allow inline blog authors, you can disable this message by setting onInlineAuthors: 'ignore' in your blog plugin options.
30
+ More info at url=${'https://docusaurus.io/docs/blog'}
31
+ `);
32
+ }
33
+ }
34
+ function reportDuplicateAuthors({ authors, blogSourceRelative, }) {
35
+ const duplicateAuthors = (0, lodash_1.default)(authors)
36
+ // for now we only check for predefined authors duplicates
37
+ .filter((author) => !!author.key)
38
+ .groupBy((author) => author.key)
39
+ .pickBy((authorsByKey) => authorsByKey.length > 1)
40
+ // We only keep the "test" of all the duplicate groups
41
+ // The first author of a group is not really a duplicate...
42
+ .flatMap(([, ...rest]) => rest)
43
+ .value();
44
+ if (duplicateAuthors.length > 0) {
45
+ throw new Error(logger_1.default.interpolate `Duplicate blog post authors were found in blog post path=${blogSourceRelative} front matter:
46
+ - ${duplicateAuthors.map(authorToString).join('\n- ')}`);
47
+ }
48
+ }
49
+ function authorToString(author) {
50
+ return JSON.stringify(author);
51
+ }
package/lib/blogUtils.js CHANGED
@@ -23,6 +23,7 @@ const utils_1 = require("@docusaurus/utils");
23
23
  const utils_validation_1 = require("@docusaurus/utils-validation");
24
24
  const frontMatter_1 = require("./frontMatter");
25
25
  const authors_1 = require("./authors");
26
+ const authorsProblems_1 = require("./authorsProblems");
26
27
  function truncate(fileString, truncateMarker) {
27
28
  return fileString.split(truncateMarker, 1).shift();
28
29
  }
@@ -196,6 +197,11 @@ async function processBlogSourceFile(blogSourceRelative, contentPaths, context,
196
197
  tagsRouteBasePath,
197
198
  ]);
198
199
  const authors = (0, authors_1.getBlogPostAuthors)({ authorsMap, frontMatter, baseUrl });
200
+ (0, authorsProblems_1.reportAuthorsProblems)({
201
+ authors,
202
+ blogSourceRelative,
203
+ options,
204
+ });
199
205
  const tags = (0, utils_1.normalizeTags)({
200
206
  options,
201
207
  source: blogSourceRelative,
package/lib/options.js CHANGED
@@ -46,6 +46,7 @@ exports.DEFAULT_OPTIONS = {
46
46
  processBlogPosts: async () => undefined,
47
47
  onInlineTags: 'warn',
48
48
  tags: undefined,
49
+ onInlineAuthors: 'warn',
49
50
  };
50
51
  const PluginOptionSchema = utils_validation_1.Joi.object({
51
52
  path: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.path),
@@ -123,6 +124,9 @@ const PluginOptionSchema = utils_validation_1.Joi.object({
123
124
  .disallow('')
124
125
  .allow(null, false)
125
126
  .default(() => exports.DEFAULT_OPTIONS.tags),
127
+ onInlineAuthors: utils_validation_1.Joi.string()
128
+ .equal('ignore', 'log', 'warn', 'throw')
129
+ .default(exports.DEFAULT_OPTIONS.onInlineAuthors),
126
130
  }).default(exports.DEFAULT_OPTIONS);
127
131
  function validateOptions({ validate, options, }) {
128
132
  const validatedOptions = validate(PluginOptionSchema, options);
package/lib/props.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  import type { TagsListItem, TagModule } from '@docusaurus/utils';
8
- import type { BlogTag, BlogTags } from '@docusaurus/plugin-content-blog';
8
+ import type { BlogPost, BlogSidebar, BlogTag, BlogTags } from '@docusaurus/plugin-content-blog';
9
9
  export declare function toTagsProp({ blogTags }: {
10
10
  blogTags: BlogTags;
11
11
  }): TagsListItem[];
@@ -13,3 +13,7 @@ export declare function toTagProp({ blogTagsListPath, tag, }: {
13
13
  blogTagsListPath: string;
14
14
  tag: BlogTag;
15
15
  }): TagModule;
16
+ export declare function toBlogSidebarProp({ blogSidebarTitle, blogPosts, }: {
17
+ blogSidebarTitle: string;
18
+ blogPosts: BlogPost[];
19
+ }): BlogSidebar;
package/lib/props.js CHANGED
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.toTagsProp = toTagsProp;
4
4
  exports.toTagProp = toTagProp;
5
+ exports.toBlogSidebarProp = toBlogSidebarProp;
5
6
  function toTagsProp({ blogTags }) {
6
7
  return Object.values(blogTags)
7
8
  .filter((tag) => !tag.unlisted)
@@ -22,3 +23,14 @@ function toTagProp({ blogTagsListPath, tag, }) {
22
23
  unlisted: tag.unlisted,
23
24
  };
24
25
  }
26
+ function toBlogSidebarProp({ blogSidebarTitle, blogPosts, }) {
27
+ return {
28
+ title: blogSidebarTitle,
29
+ items: blogPosts.map((blogPost) => ({
30
+ title: blogPost.metadata.title,
31
+ permalink: blogPost.metadata.permalink,
32
+ unlisted: blogPost.metadata.unlisted,
33
+ date: blogPost.metadata.date,
34
+ })),
35
+ };
36
+ }
package/lib/routes.js CHANGED
@@ -35,15 +35,11 @@ async function buildAllRoutes({ baseUrl, content, actions, options, aliasedSourc
35
35
  ? blogPosts
36
36
  : blogPosts.slice(0, options.blogSidebarCount);
37
37
  async function createSidebarModule() {
38
- const sidebar = {
39
- title: blogSidebarTitle,
40
- items: sidebarBlogPosts.map((blogPost) => ({
41
- title: blogPost.metadata.title,
42
- permalink: blogPost.metadata.permalink,
43
- unlisted: blogPost.metadata.unlisted,
44
- })),
45
- };
46
- const modulePath = await createData(`blog-post-list-prop-${pluginId}.json`, sidebar);
38
+ const sidebarProp = (0, props_1.toBlogSidebarProp)({
39
+ blogSidebarTitle,
40
+ blogPosts: sidebarBlogPosts,
41
+ });
42
+ const modulePath = await createData(`blog-post-list-prop-${pluginId}.json`, sidebarProp);
47
43
  return aliasedSource(modulePath);
48
44
  }
49
45
  async function createBlogMetadataModule() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@docusaurus/plugin-content-blog",
3
- "version": "0.0.0-5983",
3
+ "version": "0.0.0-5987",
4
4
  "description": "Blog plugin for Docusaurus.",
5
5
  "main": "lib/index.js",
6
6
  "types": "src/plugin-content-blog.d.ts",
@@ -31,13 +31,13 @@
31
31
  },
32
32
  "license": "MIT",
33
33
  "dependencies": {
34
- "@docusaurus/core": "0.0.0-5983",
35
- "@docusaurus/logger": "0.0.0-5983",
36
- "@docusaurus/mdx-loader": "0.0.0-5983",
37
- "@docusaurus/types": "0.0.0-5983",
38
- "@docusaurus/utils": "0.0.0-5983",
39
- "@docusaurus/utils-common": "0.0.0-5983",
40
- "@docusaurus/utils-validation": "0.0.0-5983",
34
+ "@docusaurus/core": "0.0.0-5987",
35
+ "@docusaurus/logger": "0.0.0-5987",
36
+ "@docusaurus/mdx-loader": "0.0.0-5987",
37
+ "@docusaurus/types": "0.0.0-5987",
38
+ "@docusaurus/utils": "0.0.0-5987",
39
+ "@docusaurus/utils-common": "0.0.0-5987",
40
+ "@docusaurus/utils-validation": "0.0.0-5987",
41
41
  "cheerio": "^1.0.0-rc.12",
42
42
  "feed": "^4.2.2",
43
43
  "fs-extra": "^11.1.1",
@@ -59,5 +59,5 @@
59
59
  "devDependencies": {
60
60
  "@total-typescript/shoehorn": "^0.1.2"
61
61
  },
62
- "gitHead": "303ced3b8c9e4b7674a42ebbbe73d24debeb211a"
62
+ "gitHead": "89b1afe104ab4f3fb765d2ba875d34753f77efe8"
63
63
  }
@@ -0,0 +1,72 @@
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
+
8
+ import _ from 'lodash';
9
+ import logger from '@docusaurus/logger';
10
+ import type {Author, PluginOptions} from '@docusaurus/plugin-content-blog';
11
+
12
+ export function reportAuthorsProblems(params: {
13
+ authors: Author[];
14
+ blogSourceRelative: string;
15
+ options: Pick<PluginOptions, 'onInlineAuthors' | 'authorsMapPath'>;
16
+ }): void {
17
+ reportInlineAuthors(params);
18
+ reportDuplicateAuthors(params);
19
+ }
20
+
21
+ export function reportInlineAuthors({
22
+ authors,
23
+ blogSourceRelative,
24
+ options: {onInlineAuthors, authorsMapPath},
25
+ }: {
26
+ authors: Author[];
27
+ blogSourceRelative: string;
28
+ options: Pick<PluginOptions, 'onInlineAuthors' | 'authorsMapPath'>;
29
+ }): void {
30
+ if (onInlineAuthors === 'ignore') {
31
+ return;
32
+ }
33
+ const inlineAuthors = authors.filter((author) => !author.key);
34
+ if (inlineAuthors.length > 0) {
35
+ logger.report(onInlineAuthors)(
36
+ logger.interpolate`Some blog authors used in path=${blogSourceRelative} are not defined in path=${authorsMapPath}:
37
+ - ${inlineAuthors.map(authorToString).join('\n- ')}
38
+
39
+ Note that we recommend to declare authors once in a path=${authorsMapPath} file and reference them by key in blog posts front matter to avoid author info duplication.
40
+ But if you want to allow inline blog authors, you can disable this message by setting onInlineAuthors: 'ignore' in your blog plugin options.
41
+ More info at url=${'https://docusaurus.io/docs/blog'}
42
+ `,
43
+ );
44
+ }
45
+ }
46
+
47
+ export function reportDuplicateAuthors({
48
+ authors,
49
+ blogSourceRelative,
50
+ }: {
51
+ authors: Author[];
52
+ blogSourceRelative: string;
53
+ }): void {
54
+ const duplicateAuthors = _(authors)
55
+ // for now we only check for predefined authors duplicates
56
+ .filter((author) => !!author.key)
57
+ .groupBy((author) => author.key)
58
+ .pickBy((authorsByKey) => authorsByKey.length > 1)
59
+ // We only keep the "test" of all the duplicate groups
60
+ // The first author of a group is not really a duplicate...
61
+ .flatMap(([, ...rest]) => rest)
62
+ .value();
63
+
64
+ if (duplicateAuthors.length > 0) {
65
+ throw new Error(logger.interpolate`Duplicate blog post authors were found in blog post path=${blogSourceRelative} front matter:
66
+ - ${duplicateAuthors.map(authorToString).join('\n- ')}`);
67
+ }
68
+ }
69
+
70
+ function authorToString(author: Author) {
71
+ return JSON.stringify(author);
72
+ }
package/src/blogUtils.ts CHANGED
@@ -30,6 +30,7 @@ import {
30
30
  import {getTagsFile} from '@docusaurus/utils-validation';
31
31
  import {validateBlogPostFrontMatter} from './frontMatter';
32
32
  import {type AuthorsMap, getAuthorsMap, getBlogPostAuthors} from './authors';
33
+ import {reportAuthorsProblems} from './authorsProblems';
33
34
  import type {TagsFile} from '@docusaurus/utils';
34
35
  import type {LoadContext, ParseFrontMatter} from '@docusaurus/types';
35
36
  import type {
@@ -317,7 +318,13 @@ async function processBlogSourceFile(
317
318
  routeBasePath,
318
319
  tagsRouteBasePath,
319
320
  ]);
321
+
320
322
  const authors = getBlogPostAuthors({authorsMap, frontMatter, baseUrl});
323
+ reportAuthorsProblems({
324
+ authors,
325
+ blogSourceRelative,
326
+ options,
327
+ });
321
328
 
322
329
  const tags = normalizeTags({
323
330
  options,
package/src/options.ts CHANGED
@@ -58,6 +58,7 @@ export const DEFAULT_OPTIONS: PluginOptions = {
58
58
  processBlogPosts: async () => undefined,
59
59
  onInlineTags: 'warn',
60
60
  tags: undefined,
61
+ onInlineAuthors: 'warn',
61
62
  };
62
63
 
63
64
  const PluginOptionSchema = Joi.object<PluginOptions>({
@@ -156,6 +157,9 @@ const PluginOptionSchema = Joi.object<PluginOptions>({
156
157
  .disallow('')
157
158
  .allow(null, false)
158
159
  .default(() => DEFAULT_OPTIONS.tags),
160
+ onInlineAuthors: Joi.string()
161
+ .equal('ignore', 'log', 'warn', 'throw')
162
+ .default(DEFAULT_OPTIONS.onInlineAuthors),
159
163
  }).default(DEFAULT_OPTIONS);
160
164
 
161
165
  export function validateOptions({
@@ -44,6 +44,8 @@ yarn workspace v1.22.19image` is a collocated image path, this entry will be the
44
44
  };
45
45
 
46
46
  export type Author = {
47
+ key?: string; // TODO temporary, need refactor
48
+
47
49
  /**
48
50
  * If `name` doesn't exist, an `imageURL` is expected.
49
51
  */
@@ -442,6 +444,8 @@ yarn workspace v1.22.19image` is a collocated image path, this entry will be the
442
444
  * (filter, modify, delete, etc...).
443
445
  */
444
446
  processBlogPosts: ProcessBlogPostsFn;
447
+ /** The behavior of Docusaurus when it finds inline authors. */
448
+ onInlineAuthors: 'ignore' | 'log' | 'warn' | 'throw';
445
449
  };
446
450
 
447
451
  /**
@@ -469,6 +473,7 @@ yarn workspace v1.22.19image` is a collocated image path, this entry will be the
469
473
  title: string;
470
474
  permalink: string;
471
475
  unlisted: boolean;
476
+ date: Date | string;
472
477
  };
473
478
 
474
479
  export type BlogSidebar = {
package/src/props.ts CHANGED
@@ -5,7 +5,12 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  import type {TagsListItem, TagModule} from '@docusaurus/utils';
8
- import type {BlogTag, BlogTags} from '@docusaurus/plugin-content-blog';
8
+ import type {
9
+ BlogPost,
10
+ BlogSidebar,
11
+ BlogTag,
12
+ BlogTags,
13
+ } from '@docusaurus/plugin-content-blog';
9
14
 
10
15
  export function toTagsProp({blogTags}: {blogTags: BlogTags}): TagsListItem[] {
11
16
  return Object.values(blogTags)
@@ -34,3 +39,21 @@ export function toTagProp({
34
39
  unlisted: tag.unlisted,
35
40
  };
36
41
  }
42
+
43
+ export function toBlogSidebarProp({
44
+ blogSidebarTitle,
45
+ blogPosts,
46
+ }: {
47
+ blogSidebarTitle: string;
48
+ blogPosts: BlogPost[];
49
+ }): BlogSidebar {
50
+ return {
51
+ title: blogSidebarTitle,
52
+ items: blogPosts.map((blogPost) => ({
53
+ title: blogPost.metadata.title,
54
+ permalink: blogPost.metadata.permalink,
55
+ unlisted: blogPost.metadata.unlisted,
56
+ date: blogPost.metadata.date,
57
+ })),
58
+ };
59
+ }
package/src/routes.ts CHANGED
@@ -13,7 +13,7 @@ import {
13
13
  } from '@docusaurus/utils';
14
14
  import {shouldBeListed} from './blogUtils';
15
15
 
16
- import {toTagProp, toTagsProp} from './props';
16
+ import {toBlogSidebarProp, toTagProp, toTagsProp} from './props';
17
17
  import type {
18
18
  PluginContentLoadedActions,
19
19
  RouteConfig,
@@ -26,7 +26,6 @@ import type {
26
26
  BlogContent,
27
27
  PluginOptions,
28
28
  BlogPost,
29
- BlogSidebar,
30
29
  } from '@docusaurus/plugin-content-blog';
31
30
 
32
31
  type CreateAllRoutesParam = {
@@ -88,17 +87,13 @@ export async function buildAllRoutes({
88
87
  : blogPosts.slice(0, options.blogSidebarCount);
89
88
 
90
89
  async function createSidebarModule() {
91
- const sidebar: BlogSidebar = {
92
- title: blogSidebarTitle,
93
- items: sidebarBlogPosts.map((blogPost) => ({
94
- title: blogPost.metadata.title,
95
- permalink: blogPost.metadata.permalink,
96
- unlisted: blogPost.metadata.unlisted,
97
- })),
98
- };
90
+ const sidebarProp = toBlogSidebarProp({
91
+ blogSidebarTitle,
92
+ blogPosts: sidebarBlogPosts,
93
+ });
99
94
  const modulePath = await createData(
100
95
  `blog-post-list-prop-${pluginId}.json`,
101
- sidebar,
96
+ sidebarProp,
102
97
  );
103
98
  return aliasedSource(modulePath);
104
99
  }