@docusaurus/plugin-content-blog 0.0.0-6012 → 0.0.0-6016

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,75 @@
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
+ main {
9
+ flex: 1 0 auto;
10
+ width: 100%;
11
+ margin: 2rem auto;
12
+ max-width: 800px;
13
+ /* stylelint-disable-next-line font-family-name-quotes */
14
+ font-family: system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell;
15
+ }
16
+
17
+ .info {
18
+ display: block;
19
+ margin: 2rem 0;
20
+ padding: 1.6rem 2.4rem;
21
+ border: 1px solid dodgerblue;
22
+ border-left-width: 0.5rem;
23
+ border-radius: 0.4rem;
24
+ background-color: #edf5ff;
25
+ }
26
+
27
+ a {
28
+ color: #005aff;
29
+ text-decoration: none;
30
+ }
31
+
32
+ h1 {
33
+ text-wrap: balance;
34
+ font-size: 3.4rem;
35
+ font-weight: 800;
36
+ margin-bottom: 2rem;
37
+ display: flex;
38
+ align-items: center;
39
+ }
40
+
41
+ h1 .rss-icon {
42
+ height: 3.2rem;
43
+ width: 3.2rem;
44
+ margin-right: 1rem;
45
+ }
46
+
47
+ h2 {
48
+ font-size: 2.2rem;
49
+ font-weight: 700;
50
+ margin-bottom: 0.2rem;
51
+ }
52
+
53
+ h3 {
54
+ font-size: 1.8rem;
55
+ font-weight: 700;
56
+ margin-bottom: 0.1rem;
57
+ }
58
+
59
+ .blog-description {
60
+ font-size: 1.4rem;
61
+ margin-bottom: 0.6rem;
62
+ }
63
+
64
+ .blog-post-date {
65
+ font-size: 1rem;
66
+ line-height: 1.4rem;
67
+ font-style: italic;
68
+ color: #797b7e;
69
+ }
70
+
71
+ .blog-post-description {
72
+ font-size: 1rem;
73
+ line-height: 1.4rem;
74
+ color: #434349;
75
+ }
@@ -0,0 +1,92 @@
1
+ <?xml version="1.0" encoding="UTF-8" ?>
2
+ <xsl:stylesheet
3
+ version="3.0"
4
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
5
+ xmlns:atom="http://www.w3.org/2005/Atom">
6
+ <xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes" />
7
+
8
+ <xsl:template match="/">
9
+ <html xmlns="http://www.w3.org/1999/xhtml" lang="en">
10
+ <head>
11
+ <title>Atom Feed | <xsl:value-of
12
+ select="atom:feed/atom:title"
13
+ /></title>
14
+ <link rel="stylesheet" href="atom.css" />
15
+ </head>
16
+ <body>
17
+ <main>
18
+ <div class="description">
19
+ <div class="info">
20
+ <strong>This is an Atom feed</strong>. Subscribe by copying the URL
21
+ from the address bar into your newsreader. Visit
22
+ <a href="https://aboutfeeds.com/">About Feeds</a> to learn more
23
+ and get started. It’s free.
24
+ </div>
25
+ <h1>
26
+ <div class="rss-icon">
27
+ <svg
28
+ version="1.1"
29
+ id="Capa_1"
30
+ xmlns="http://www.w3.org/2000/svg"
31
+ xmlns:xlink="http://www.w3.org/1999/xlink"
32
+ viewBox="0 0 455.731 455.731"
33
+ xml:space="preserve">
34
+ <g>
35
+ <rect
36
+ x="0"
37
+ y="0"
38
+ style="fill: #f78422"
39
+ width="455.731"
40
+ height="455.731"
41
+ />
42
+ <g>
43
+ <path
44
+ style="fill: #ffffff"
45
+ d="M296.208,159.16C234.445,97.397,152.266,63.382,64.81,63.382v64.348
46
+ c70.268,0,136.288,27.321,185.898,76.931c49.609,49.61,76.931,115.63,76.931,185.898h64.348
47
+ C391.986,303.103,357.971,220.923,296.208,159.16z"
48
+ />
49
+ <path
50
+ style="fill: #ffffff"
51
+ d="M64.143,172.273v64.348c84.881,0,153.938,69.056,153.938,153.939h64.348
52
+ C282.429,270.196,184.507,172.273,64.143,172.273z"
53
+ />
54
+ <circle
55
+ style="fill: #ffffff"
56
+ cx="109.833"
57
+ cy="346.26"
58
+ r="46.088"
59
+ />
60
+ </g>
61
+ </g>
62
+ </svg>
63
+ </div>
64
+ <xsl:value-of select="atom:feed/atom:title" />
65
+ </h1>
66
+ <p class="blog-description">
67
+ <xsl:value-of select="atom:feed/atom:subtitle" />
68
+ </p>
69
+ </div>
70
+ <h2>Recent Posts</h2>
71
+ <div class="blog-posts">
72
+ <xsl:for-each select="atom:feed/atom:entry">
73
+ <div class="blog-post">
74
+ <h3><a href="{atom:link[@rel='alternate']/@href}"><xsl:value-of
75
+ select="atom:title"
76
+ /></a></h3>
77
+ <div class="blog-post-date">
78
+ Published on <xsl:value-of
79
+ select="substring(atom:updated,0,11)"
80
+ />
81
+ </div>
82
+ <div class="blog-post-description">
83
+ <xsl:value-of select="atom:summary" />
84
+ </div>
85
+ </div>
86
+ </xsl:for-each>
87
+ </div>
88
+ </main>
89
+ </body>
90
+ </html>
91
+ </xsl:template>
92
+ </xsl:stylesheet>
package/assets/rss.css ADDED
@@ -0,0 +1,75 @@
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
+ main {
9
+ flex: 1 0 auto;
10
+ width: 100%;
11
+ margin: 2rem auto;
12
+ max-width: 800px;
13
+ /* stylelint-disable-next-line font-family-name-quotes */
14
+ font-family: system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell;
15
+ }
16
+
17
+ .info {
18
+ display: block;
19
+ margin: 2rem 0;
20
+ padding: 1.6rem 2.4rem;
21
+ border: 1px solid dodgerblue;
22
+ border-left-width: 0.5rem;
23
+ border-radius: 0.4rem;
24
+ background-color: #edf5ff;
25
+ }
26
+
27
+ a {
28
+ color: #005aff;
29
+ text-decoration: none;
30
+ }
31
+
32
+ h1 {
33
+ text-wrap: balance;
34
+ font-size: 3.4rem;
35
+ font-weight: 800;
36
+ margin-bottom: 2rem;
37
+ display: flex;
38
+ align-items: center;
39
+ }
40
+
41
+ h1 .rss-icon {
42
+ height: 3.2rem;
43
+ width: 3.2rem;
44
+ margin-right: 1rem;
45
+ }
46
+
47
+ h2 {
48
+ font-size: 2.2rem;
49
+ font-weight: 700;
50
+ margin-bottom: 0.2rem;
51
+ }
52
+
53
+ h3 {
54
+ font-size: 1.8rem;
55
+ font-weight: 700;
56
+ margin-bottom: 0.1rem;
57
+ }
58
+
59
+ .blog-description {
60
+ font-size: 1.4rem;
61
+ margin-bottom: 0.6rem;
62
+ }
63
+
64
+ .blog-post-date {
65
+ font-size: 1rem;
66
+ line-height: 1.4rem;
67
+ font-style: italic;
68
+ color: #797b7e;
69
+ }
70
+
71
+ .blog-post-description {
72
+ font-size: 1rem;
73
+ line-height: 1.4rem;
74
+ color: #434349;
75
+ }
package/assets/rss.xsl ADDED
@@ -0,0 +1,86 @@
1
+ <?xml version="1.0" encoding="UTF-8" ?>
2
+ <xsl:stylesheet
3
+ version="3.0"
4
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
5
+ xmlns:atom="http://www.w3.org/2005/Atom">
6
+ <xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes" />
7
+
8
+ <xsl:template match="/">
9
+ <html xmlns="http://www.w3.org/1999/xhtml" lang="en">
10
+ <head>
11
+ <title>RSS Feed | <xsl:value-of select="rss/channel/title" /></title>
12
+ <link rel="stylesheet" href="rss.css" />
13
+ </head>
14
+ <body>
15
+ <main>
16
+ <div class="description">
17
+ <div class="info">
18
+ <strong>This is an RSS feed</strong>. Subscribe by copying the URL
19
+ from the address bar into your newsreader. Visit
20
+ <a href="https://aboutfeeds.com/">About Feeds</a> to learn more
21
+ and get started. It’s free.
22
+ </div>
23
+ <h1>
24
+ <div class="rss-icon">
25
+ <svg
26
+ version="1.1"
27
+ id="Capa_1"
28
+ xmlns="http://www.w3.org/2000/svg"
29
+ xmlns:xlink="http://www.w3.org/1999/xlink"
30
+ viewBox="0 0 455.731 455.731"
31
+ xml:space="preserve">
32
+ <g>
33
+ <rect
34
+ x="0"
35
+ y="0"
36
+ style="fill: #f78422"
37
+ width="455.731"
38
+ height="455.731"
39
+ />
40
+ <g>
41
+ <path
42
+ style="fill: #ffffff"
43
+ d="M296.208,159.16C234.445,97.397,152.266,63.382,64.81,63.382v64.348
44
+ c70.268,0,136.288,27.321,185.898,76.931c49.609,49.61,76.931,115.63,76.931,185.898h64.348
45
+ C391.986,303.103,357.971,220.923,296.208,159.16z"
46
+ />
47
+ <path
48
+ style="fill: #ffffff"
49
+ d="M64.143,172.273v64.348c84.881,0,153.938,69.056,153.938,153.939h64.348
50
+ C282.429,270.196,184.507,172.273,64.143,172.273z"
51
+ />
52
+ <circle
53
+ style="fill: #ffffff"
54
+ cx="109.833"
55
+ cy="346.26"
56
+ r="46.088"
57
+ />
58
+ </g>
59
+ </g>
60
+ </svg>
61
+ </div>
62
+ <xsl:value-of select="rss/channel/title" />
63
+ </h1>
64
+ <p class="blog-description">
65
+ <xsl:value-of select="rss/channel/description" />
66
+ </p>
67
+ </div>
68
+ <h2>Recent Posts</h2>
69
+ <div class="blog-posts">
70
+ <xsl:for-each select="rss/channel/item">
71
+ <div class="blog-post">
72
+ <h3><a href="{link}"><xsl:value-of select="title" /></a></h3>
73
+ <div class="blog-post-date">
74
+ Published on <xsl:value-of select="substring(pubDate,0,17)" />
75
+ </div>
76
+ <div class="blog-post-description">
77
+ <xsl:value-of select="description" />
78
+ </div>
79
+ </div>
80
+ </xsl:for-each>
81
+ </div>
82
+ </main>
83
+ </body>
84
+ </html>
85
+ </xsl:template>
86
+ </xsl:stylesheet>
package/lib/authors.d.ts CHANGED
@@ -4,20 +4,19 @@
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
- import type { BlogContentPaths } from './types';
8
- import type { Author, BlogPostFrontMatter } from '@docusaurus/plugin-content-blog';
9
- export type AuthorsMap = {
10
- [authorKey: string]: Author;
11
- };
12
- export declare function validateAuthorsMap(content: unknown): AuthorsMap;
13
- export declare function getAuthorsMap(params: {
14
- authorsMapPath: string;
15
- contentPaths: BlogContentPaths;
16
- }): Promise<AuthorsMap | undefined>;
7
+ import type { Author, AuthorsMap, BlogPost, BlogPostFrontMatter } from '@docusaurus/plugin-content-blog';
17
8
  type AuthorsParam = {
18
9
  frontMatter: BlogPostFrontMatter;
19
10
  authorsMap: AuthorsMap | undefined;
20
11
  baseUrl: string;
21
12
  };
22
13
  export declare function getBlogPostAuthors(params: AuthorsParam): Author[];
14
+ /**
15
+ * Group blog posts by author key
16
+ * Blog posts with only inline authors are ignored
17
+ */
18
+ export declare function groupBlogPostsByAuthorKey({ blogPosts, authorsMap, }: {
19
+ blogPosts: BlogPost[];
20
+ authorsMap: AuthorsMap | undefined;
21
+ }): Record<string, BlogPost[]>;
23
22
  export {};
package/lib/authors.js CHANGED
@@ -6,60 +6,11 @@
6
6
  * LICENSE file in the root directory of this source tree.
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.validateAuthorsMap = validateAuthorsMap;
10
- exports.getAuthorsMap = getAuthorsMap;
11
9
  exports.getBlogPostAuthors = getBlogPostAuthors;
10
+ exports.groupBlogPostsByAuthorKey = groupBlogPostsByAuthorKey;
12
11
  const tslib_1 = require("tslib");
13
- const _ = tslib_1.__importStar(require("lodash"));
12
+ const lodash_1 = tslib_1.__importDefault(require("lodash"));
14
13
  const utils_1 = require("@docusaurus/utils");
15
- const utils_validation_1 = require("@docusaurus/utils-validation");
16
- const authorsSocials_1 = require("./authorsSocials");
17
- const AuthorsMapSchema = utils_validation_1.Joi.object()
18
- .pattern(utils_validation_1.Joi.string(), utils_validation_1.Joi.object({
19
- name: utils_validation_1.Joi.string(),
20
- url: utils_validation_1.URISchema,
21
- imageURL: utils_validation_1.URISchema,
22
- title: utils_validation_1.Joi.string(),
23
- email: utils_validation_1.Joi.string(),
24
- socials: authorsSocials_1.AuthorSocialsSchema,
25
- })
26
- .rename('image_url', 'imageURL')
27
- .or('name', 'imageURL')
28
- .unknown()
29
- .required()
30
- .messages({
31
- 'object.base': '{#label} should be an author object containing properties like name, title, and imageURL.',
32
- 'any.required': '{#label} cannot be undefined. It should be an author object containing properties like name, title, and imageURL.',
33
- }))
34
- .messages({
35
- 'object.base': "The authors map file should contain an object where each entry contains an author key and the corresponding author's data.",
36
- });
37
- function validateAuthorsMap(content) {
38
- const { error, value } = AuthorsMapSchema.validate(content);
39
- if (error) {
40
- throw error;
41
- }
42
- return value;
43
- }
44
- function normalizeAuthor(author) {
45
- return {
46
- ...author,
47
- socials: author.socials ? (0, authorsSocials_1.normalizeSocials)(author.socials) : undefined,
48
- };
49
- }
50
- function normalizeAuthorsMap(authorsMap) {
51
- return _.mapValues(authorsMap, normalizeAuthor);
52
- }
53
- async function getAuthorsMap(params) {
54
- const authorsMap = await (0, utils_1.getDataFileData)({
55
- filePath: params.authorsMapPath,
56
- contentPaths: params.contentPaths,
57
- fileType: 'authors map',
58
- },
59
- // TODO annoying to test: tightly coupled FS reads + validation...
60
- validateAuthorsMap);
61
- return authorsMap ? normalizeAuthorsMap(authorsMap) : undefined;
62
- }
63
14
  function normalizeImageUrl({ imageURL, baseUrl, }) {
64
15
  return imageURL?.startsWith('/')
65
16
  ? (0, utils_1.normalizeUrl)([baseUrl, imageURL])
@@ -67,6 +18,7 @@ function normalizeImageUrl({ imageURL, baseUrl, }) {
67
18
  }
68
19
  // Legacy v1/early-v2 front matter fields
69
20
  // We may want to deprecate those in favor of using only frontMatter.authors
21
+ // TODO Docusaurus v4: remove this legacy front matter
70
22
  function getFrontMatterAuthorLegacy({ baseUrl, frontMatter, }) {
71
23
  const name = frontMatter.author;
72
24
  const title = frontMatter.author_title ?? frontMatter.authorTitle;
@@ -81,27 +33,33 @@ function getFrontMatterAuthorLegacy({ baseUrl, frontMatter, }) {
81
33
  title,
82
34
  url,
83
35
  imageURL,
36
+ // legacy front matter authors do not have an author key/page
37
+ key: null,
38
+ page: null,
84
39
  };
85
40
  }
86
41
  return undefined;
87
42
  }
88
- function normalizeFrontMatterAuthors(frontMatterAuthors = []) {
89
- function normalizeFrontMatterAuthor(authorInput) {
90
- if (typeof authorInput === 'string') {
91
- // Technically, we could allow users to provide an author's name here, but
92
- // we only support keys, otherwise, a typo in a key would fallback to
93
- // becoming a name and may end up unnoticed
94
- return { key: authorInput };
43
+ function getFrontMatterAuthors(params) {
44
+ const { authorsMap, frontMatter, baseUrl } = params;
45
+ return normalizeFrontMatterAuthors().map(toAuthor);
46
+ function normalizeFrontMatterAuthors() {
47
+ if (frontMatter.authors === undefined) {
48
+ return [];
49
+ }
50
+ function normalizeAuthor(authorInput) {
51
+ if (typeof authorInput === 'string') {
52
+ // We could allow users to provide an author's name here, but we only
53
+ // support keys, otherwise, a typo in a key would fall back to
54
+ // becoming a name and may end up unnoticed
55
+ return { key: authorInput };
56
+ }
57
+ return authorInput;
95
58
  }
96
- return authorInput;
59
+ return Array.isArray(frontMatter.authors)
60
+ ? frontMatter.authors.map(normalizeAuthor)
61
+ : [normalizeAuthor(frontMatter.authors)];
97
62
  }
98
- return Array.isArray(frontMatterAuthors)
99
- ? frontMatterAuthors.map(normalizeFrontMatterAuthor)
100
- : [normalizeFrontMatterAuthor(frontMatterAuthors)];
101
- }
102
- function getFrontMatterAuthors(params) {
103
- const { authorsMap } = params;
104
- const frontMatterAuthors = normalizeFrontMatterAuthors(params.frontMatter.authors);
105
63
  function getAuthorsMapAuthor(key) {
106
64
  if (key) {
107
65
  if (!authorsMap || Object.keys(authorsMap).length === 0) {
@@ -121,32 +79,37 @@ ${Object.keys(authorsMap)
121
79
  return undefined;
122
80
  }
123
81
  function toAuthor(frontMatterAuthor) {
124
- return normalizeAuthor({
82
+ const author = {
125
83
  // Author def from authorsMap can be locally overridden by front matter
126
84
  ...getAuthorsMapAuthor(frontMatterAuthor.key),
127
85
  ...frontMatterAuthor,
128
- });
86
+ };
87
+ return {
88
+ ...author,
89
+ key: author.key ?? null,
90
+ page: author.page ?? null,
91
+ imageURL: normalizeImageUrl({ imageURL: author.imageURL, baseUrl }),
92
+ };
129
93
  }
130
- return frontMatterAuthors.map(toAuthor);
131
- }
132
- function fixAuthorImageBaseURL(authors, { baseUrl }) {
133
- return authors.map((author) => ({
134
- ...author,
135
- imageURL: normalizeImageUrl({ imageURL: author.imageURL, baseUrl }),
136
- }));
137
94
  }
138
95
  function getBlogPostAuthors(params) {
139
96
  const authorLegacy = getFrontMatterAuthorLegacy(params);
140
97
  const authors = getFrontMatterAuthors(params);
141
- const updatedAuthors = fixAuthorImageBaseURL(authors, params);
142
98
  if (authorLegacy) {
143
99
  // Technically, we could allow mixing legacy/authors front matter, but do we
144
100
  // really want to?
145
- if (updatedAuthors.length > 0) {
101
+ if (authors.length > 0) {
146
102
  throw new Error(`To declare blog post authors, use the 'authors' front matter in priority.
147
103
  Don't mix 'authors' with other existing 'author_*' front matter. Choose one or the other, not both at the same time.`);
148
104
  }
149
105
  return [authorLegacy];
150
106
  }
151
- return updatedAuthors;
107
+ return authors;
108
+ }
109
+ /**
110
+ * Group blog posts by author key
111
+ * Blog posts with only inline authors are ignored
112
+ */
113
+ function groupBlogPostsByAuthorKey({ blogPosts, authorsMap, }) {
114
+ return lodash_1.default.mapValues(authorsMap, (author, key) => blogPosts.filter((p) => p.metadata.authors.some((a) => a.key === key)));
152
115
  }
@@ -0,0 +1,23 @@
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 { BlogContentPaths } from './types';
8
+ import type { AuthorAttributes, AuthorPage, AuthorsMap } from '@docusaurus/plugin-content-blog';
9
+ type AuthorInput = AuthorAttributes & {
10
+ page?: boolean | AuthorPage;
11
+ };
12
+ export type AuthorsMapInput = {
13
+ [authorKey: string]: AuthorInput;
14
+ };
15
+ export declare function checkAuthorsMapPermalinkCollisions(authorsMap: AuthorsMap | undefined): void;
16
+ export declare function validateAuthorsMapInput(content: unknown): AuthorsMapInput;
17
+ export declare function getAuthorsMap(params: {
18
+ authorsMapPath: string;
19
+ authorsBaseRoutePath: string;
20
+ contentPaths: BlogContentPaths;
21
+ }): Promise<AuthorsMap | undefined>;
22
+ export declare function validateAuthorsMap(content: unknown): AuthorsMapInput;
23
+ export {};
@@ -0,0 +1,116 @@
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.checkAuthorsMapPermalinkCollisions = checkAuthorsMapPermalinkCollisions;
10
+ exports.validateAuthorsMapInput = validateAuthorsMapInput;
11
+ exports.getAuthorsMap = getAuthorsMap;
12
+ exports.validateAuthorsMap = validateAuthorsMap;
13
+ const tslib_1 = require("tslib");
14
+ const lodash_1 = tslib_1.__importDefault(require("lodash"));
15
+ const utils_1 = require("@docusaurus/utils");
16
+ const utils_validation_1 = require("@docusaurus/utils-validation");
17
+ const authorsSocials_1 = require("./authorsSocials");
18
+ const AuthorPageSchema = utils_validation_1.Joi.object({
19
+ permalink: utils_validation_1.Joi.string().required(),
20
+ });
21
+ const AuthorsMapInputSchema = utils_validation_1.Joi.object()
22
+ .pattern(utils_validation_1.Joi.string(), utils_validation_1.Joi.object({
23
+ name: utils_validation_1.Joi.string(),
24
+ url: utils_validation_1.URISchema,
25
+ imageURL: utils_validation_1.URISchema,
26
+ title: utils_validation_1.Joi.string(),
27
+ email: utils_validation_1.Joi.string(),
28
+ page: utils_validation_1.Joi.alternatives(utils_validation_1.Joi.bool(), AuthorPageSchema),
29
+ socials: authorsSocials_1.AuthorSocialsSchema,
30
+ description: utils_validation_1.Joi.string(),
31
+ })
32
+ .rename('image_url', 'imageURL')
33
+ .or('name', 'imageURL')
34
+ .unknown()
35
+ .required()
36
+ .messages({
37
+ 'object.base': '{#label} should be an author object containing properties like name, title, and imageURL.',
38
+ 'any.required': '{#label} cannot be undefined. It should be an author object containing properties like name, title, and imageURL.',
39
+ }))
40
+ .messages({
41
+ 'object.base': "The authors map file should contain an object where each entry contains an author key and the corresponding author's data.",
42
+ });
43
+ function checkAuthorsMapPermalinkCollisions(authorsMap) {
44
+ if (!authorsMap) {
45
+ return;
46
+ }
47
+ const permalinkCounts = (0, lodash_1.default)(authorsMap)
48
+ // Filter to keep only authors with a page
49
+ .pickBy((author) => !!author.page)
50
+ // Group authors by their permalink
51
+ .groupBy((author) => author.page?.permalink)
52
+ // Filter to keep only permalinks with more than one author
53
+ .pickBy((authors) => authors.length > 1)
54
+ // Transform the object into an array of [permalink, authors] pairs
55
+ .toPairs()
56
+ .value();
57
+ if (permalinkCounts.length > 0) {
58
+ const errorMessage = permalinkCounts
59
+ .map(([permalink, authors]) => `Permalink: ${permalink}\nAuthors: ${authors
60
+ .map((author) => author.name || 'Unknown')
61
+ .join(', ')}`)
62
+ .join('\n');
63
+ throw new Error(`The following permalinks are duplicated:\n${errorMessage}`);
64
+ }
65
+ }
66
+ function normalizeAuthor({ authorsBaseRoutePath, authorKey, author, }) {
67
+ function getAuthorPage() {
68
+ if (!author.page) {
69
+ return null;
70
+ }
71
+ const slug = author.page === true ? lodash_1.default.kebabCase(authorKey) : author.page.permalink;
72
+ return {
73
+ permalink: (0, utils_1.normalizeUrl)([authorsBaseRoutePath, slug]),
74
+ };
75
+ }
76
+ return {
77
+ ...author,
78
+ key: authorKey,
79
+ page: getAuthorPage(),
80
+ socials: author.socials ? (0, authorsSocials_1.normalizeSocials)(author.socials) : undefined,
81
+ };
82
+ }
83
+ function normalizeAuthorsMap({ authorsBaseRoutePath, authorsMapInput, }) {
84
+ return lodash_1.default.mapValues(authorsMapInput, (author, authorKey) => {
85
+ return normalizeAuthor({ authorsBaseRoutePath, authorKey, author });
86
+ });
87
+ }
88
+ function validateAuthorsMapInput(content) {
89
+ const { error, value } = AuthorsMapInputSchema.validate(content);
90
+ if (error) {
91
+ throw error;
92
+ }
93
+ return value;
94
+ }
95
+ async function getAuthorsMapInput(params) {
96
+ const content = await (0, utils_1.readDataFile)({
97
+ filePath: params.authorsMapPath,
98
+ contentPaths: params.contentPaths,
99
+ });
100
+ return content ? validateAuthorsMapInput(content) : undefined;
101
+ }
102
+ async function getAuthorsMap(params) {
103
+ const authorsMapInput = await getAuthorsMapInput(params);
104
+ if (!authorsMapInput) {
105
+ return undefined;
106
+ }
107
+ const authorsMap = normalizeAuthorsMap({ authorsMapInput, ...params });
108
+ return authorsMap;
109
+ }
110
+ function validateAuthorsMap(content) {
111
+ const { error, value } = AuthorsMapInputSchema.validate(content);
112
+ if (error) {
113
+ throw error;
114
+ }
115
+ return value;
116
+ }
@@ -5,7 +5,7 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  import type { LoadContext } from '@docusaurus/types';
8
- import type { PluginOptions, BlogPost, BlogTags, BlogPaginated } from '@docusaurus/plugin-content-blog';
8
+ import type { AuthorsMap, PluginOptions, BlogPost, BlogTags, BlogPaginated } from '@docusaurus/plugin-content-blog';
9
9
  import type { BlogContentPaths } from './types';
10
10
  export declare function truncate(fileString: string, truncateMarker: RegExp): string;
11
11
  export declare function paginateBlogPosts({ blogPosts, basePageUrl, blogTitle, blogDescription, postsPerPageOption, pageBasePath, }: {
@@ -30,7 +30,7 @@ type ParsedBlogFileName = {
30
30
  slug: string;
31
31
  };
32
32
  export declare function parseBlogFileName(blogSourceRelative: string): ParsedBlogFileName;
33
- export declare function generateBlogPosts(contentPaths: BlogContentPaths, context: LoadContext, options: PluginOptions): Promise<BlogPost[]>;
33
+ export declare function generateBlogPosts(contentPaths: BlogContentPaths, context: LoadContext, options: PluginOptions, authorsMap?: AuthorsMap): Promise<BlogPost[]>;
34
34
  export declare function applyProcessBlogPosts({ blogPosts, processBlogPosts, }: {
35
35
  blogPosts: BlogPost[];
36
36
  processBlogPosts: PluginOptions['processBlogPosts'];