@docusaurus/plugin-content-blog 3.3.2 → 3.5.0
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/assets/atom.css +75 -0
- package/assets/atom.xsl +92 -0
- package/assets/rss.css +75 -0
- package/assets/rss.xsl +86 -0
- package/lib/authors.d.ts +9 -11
- package/lib/authors.js +42 -64
- package/lib/authorsMap.d.ts +23 -0
- package/lib/authorsMap.js +116 -0
- package/lib/authorsProblems.d.ts +21 -0
- package/lib/authorsProblems.js +51 -0
- package/lib/authorsSocials.d.ts +10 -0
- package/lib/authorsSocials.js +48 -0
- package/lib/blogUtils.d.ts +7 -12
- package/lib/blogUtils.js +44 -34
- package/lib/client/contexts.d.ts +33 -0
- package/lib/client/contexts.js +54 -0
- package/lib/client/index.d.ts +3 -3
- package/lib/client/index.js +3 -9
- package/lib/client/sidebarUtils.d.ts +21 -0
- package/lib/client/sidebarUtils.js +49 -0
- package/lib/client/sidebarUtils.test.d.ts +7 -0
- package/lib/client/sidebarUtils.test.js +43 -0
- package/lib/client/structuredDataUtils.d.ts +10 -0
- package/lib/client/structuredDataUtils.js +122 -0
- package/lib/feed.d.ts +8 -3
- package/lib/feed.js +111 -20
- package/lib/frontMatter.d.ts +0 -1
- package/lib/frontMatter.js +3 -2
- package/lib/index.d.ts +0 -1
- package/lib/index.js +132 -105
- package/lib/markdownLoader.js +3 -7
- package/lib/options.d.ts +4 -1
- package/lib/options.js +107 -26
- package/lib/props.d.ts +9 -2
- package/lib/props.js +23 -3
- package/lib/remark/footnoteIDFixer.js +1 -1
- package/lib/routes.d.ts +0 -1
- package/lib/routes.js +82 -14
- package/lib/translations.d.ts +0 -1
- package/lib/translations.js +2 -3
- package/lib/types.d.ts +1 -8
- package/package.json +13 -10
- package/src/authors.ts +56 -93
- package/src/authorsMap.ts +171 -0
- package/src/authorsProblems.ts +72 -0
- package/src/authorsSocials.ts +64 -0
- package/src/blogUtils.ts +51 -46
- package/src/client/contexts.tsx +95 -0
- package/src/client/index.tsx +24 -0
- package/src/client/sidebarUtils.test.ts +52 -0
- package/src/client/sidebarUtils.tsx +85 -0
- package/src/client/structuredDataUtils.ts +178 -0
- package/src/feed.ts +197 -18
- package/src/frontMatter.ts +2 -0
- package/src/index.ts +182 -137
- package/src/markdownLoader.ts +3 -7
- package/src/options.ts +132 -32
- package/src/plugin-content-blog.d.ts +252 -113
- package/src/props.ts +41 -1
- package/src/routes.ts +102 -12
- package/src/types.ts +1 -6
- package/src/client/index.ts +0 -20
package/assets/atom.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/atom.xsl
ADDED
|
@@ -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,21 +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
|
-
|
|
8
|
-
import type { BlogContentPaths } from './types';
|
|
9
|
-
import type { Author, BlogPostFrontMatter } from '@docusaurus/plugin-content-blog';
|
|
10
|
-
export type AuthorsMap = {
|
|
11
|
-
[authorKey: string]: Author;
|
|
12
|
-
};
|
|
13
|
-
export declare function validateAuthorsMap(content: unknown): AuthorsMap;
|
|
14
|
-
export declare function getAuthorsMap(params: {
|
|
15
|
-
authorsMapPath: string;
|
|
16
|
-
contentPaths: BlogContentPaths;
|
|
17
|
-
}): Promise<AuthorsMap | undefined>;
|
|
7
|
+
import type { Author, AuthorsMap, BlogPost, BlogPostFrontMatter } from '@docusaurus/plugin-content-blog';
|
|
18
8
|
type AuthorsParam = {
|
|
19
9
|
frontMatter: BlogPostFrontMatter;
|
|
20
10
|
authorsMap: AuthorsMap | undefined;
|
|
21
11
|
baseUrl: string;
|
|
22
12
|
};
|
|
23
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[]>;
|
|
24
22
|
export {};
|
package/lib/authors.js
CHANGED
|
@@ -6,44 +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.getBlogPostAuthors =
|
|
9
|
+
exports.getBlogPostAuthors = getBlogPostAuthors;
|
|
10
|
+
exports.groupBlogPostsByAuthorKey = groupBlogPostsByAuthorKey;
|
|
11
|
+
const tslib_1 = require("tslib");
|
|
12
|
+
const lodash_1 = tslib_1.__importDefault(require("lodash"));
|
|
10
13
|
const utils_1 = require("@docusaurus/utils");
|
|
11
|
-
const utils_validation_1 = require("@docusaurus/utils-validation");
|
|
12
|
-
const AuthorsMapSchema = utils_validation_1.Joi.object()
|
|
13
|
-
.pattern(utils_validation_1.Joi.string(), utils_validation_1.Joi.object({
|
|
14
|
-
name: utils_validation_1.Joi.string(),
|
|
15
|
-
url: utils_validation_1.URISchema,
|
|
16
|
-
imageURL: utils_validation_1.URISchema,
|
|
17
|
-
title: utils_validation_1.Joi.string(),
|
|
18
|
-
email: utils_validation_1.Joi.string(),
|
|
19
|
-
})
|
|
20
|
-
.rename('image_url', 'imageURL')
|
|
21
|
-
.or('name', 'imageURL')
|
|
22
|
-
.unknown()
|
|
23
|
-
.required()
|
|
24
|
-
.messages({
|
|
25
|
-
'object.base': '{#label} should be an author object containing properties like name, title, and imageURL.',
|
|
26
|
-
'any.required': '{#label} cannot be undefined. It should be an author object containing properties like name, title, and imageURL.',
|
|
27
|
-
}))
|
|
28
|
-
.messages({
|
|
29
|
-
'object.base': "The authors map file should contain an object where each entry contains an author key and the corresponding author's data.",
|
|
30
|
-
});
|
|
31
|
-
function validateAuthorsMap(content) {
|
|
32
|
-
const { error, value } = AuthorsMapSchema.validate(content);
|
|
33
|
-
if (error) {
|
|
34
|
-
throw error;
|
|
35
|
-
}
|
|
36
|
-
return value;
|
|
37
|
-
}
|
|
38
|
-
exports.validateAuthorsMap = validateAuthorsMap;
|
|
39
|
-
async function getAuthorsMap(params) {
|
|
40
|
-
return (0, utils_1.getDataFileData)({
|
|
41
|
-
filePath: params.authorsMapPath,
|
|
42
|
-
contentPaths: params.contentPaths,
|
|
43
|
-
fileType: 'authors map',
|
|
44
|
-
}, validateAuthorsMap);
|
|
45
|
-
}
|
|
46
|
-
exports.getAuthorsMap = getAuthorsMap;
|
|
47
14
|
function normalizeImageUrl({ imageURL, baseUrl, }) {
|
|
48
15
|
return imageURL?.startsWith('/')
|
|
49
16
|
? (0, utils_1.normalizeUrl)([baseUrl, imageURL])
|
|
@@ -51,6 +18,7 @@ function normalizeImageUrl({ imageURL, baseUrl, }) {
|
|
|
51
18
|
}
|
|
52
19
|
// Legacy v1/early-v2 front matter fields
|
|
53
20
|
// We may want to deprecate those in favor of using only frontMatter.authors
|
|
21
|
+
// TODO Docusaurus v4: remove this legacy front matter
|
|
54
22
|
function getFrontMatterAuthorLegacy({ baseUrl, frontMatter, }) {
|
|
55
23
|
const name = frontMatter.author;
|
|
56
24
|
const title = frontMatter.author_title ?? frontMatter.authorTitle;
|
|
@@ -65,27 +33,33 @@ function getFrontMatterAuthorLegacy({ baseUrl, frontMatter, }) {
|
|
|
65
33
|
title,
|
|
66
34
|
url,
|
|
67
35
|
imageURL,
|
|
36
|
+
// legacy front matter authors do not have an author key/page
|
|
37
|
+
key: null,
|
|
38
|
+
page: null,
|
|
68
39
|
};
|
|
69
40
|
}
|
|
70
41
|
return undefined;
|
|
71
42
|
}
|
|
72
|
-
function
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
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 [];
|
|
79
49
|
}
|
|
80
|
-
|
|
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;
|
|
58
|
+
}
|
|
59
|
+
return Array.isArray(frontMatter.authors)
|
|
60
|
+
? frontMatter.authors.map(normalizeAuthor)
|
|
61
|
+
: [normalizeAuthor(frontMatter.authors)];
|
|
81
62
|
}
|
|
82
|
-
return Array.isArray(frontMatterAuthors)
|
|
83
|
-
? frontMatterAuthors.map(normalizeAuthor)
|
|
84
|
-
: [normalizeAuthor(frontMatterAuthors)];
|
|
85
|
-
}
|
|
86
|
-
function getFrontMatterAuthors(params) {
|
|
87
|
-
const { authorsMap } = params;
|
|
88
|
-
const frontMatterAuthors = normalizeFrontMatterAuthors(params.frontMatter.authors);
|
|
89
63
|
function getAuthorsMapAuthor(key) {
|
|
90
64
|
if (key) {
|
|
91
65
|
if (!authorsMap || Object.keys(authorsMap).length === 0) {
|
|
@@ -105,33 +79,37 @@ ${Object.keys(authorsMap)
|
|
|
105
79
|
return undefined;
|
|
106
80
|
}
|
|
107
81
|
function toAuthor(frontMatterAuthor) {
|
|
108
|
-
|
|
82
|
+
const author = {
|
|
109
83
|
// Author def from authorsMap can be locally overridden by front matter
|
|
110
84
|
...getAuthorsMapAuthor(frontMatterAuthor.key),
|
|
111
85
|
...frontMatterAuthor,
|
|
112
86
|
};
|
|
87
|
+
return {
|
|
88
|
+
...author,
|
|
89
|
+
key: author.key ?? null,
|
|
90
|
+
page: author.page ?? null,
|
|
91
|
+
imageURL: normalizeImageUrl({ imageURL: author.imageURL, baseUrl }),
|
|
92
|
+
};
|
|
113
93
|
}
|
|
114
|
-
return frontMatterAuthors.map(toAuthor);
|
|
115
|
-
}
|
|
116
|
-
function fixAuthorImageBaseURL(authors, { baseUrl }) {
|
|
117
|
-
return authors.map((author) => ({
|
|
118
|
-
...author,
|
|
119
|
-
imageURL: normalizeImageUrl({ imageURL: author.imageURL, baseUrl }),
|
|
120
|
-
}));
|
|
121
94
|
}
|
|
122
95
|
function getBlogPostAuthors(params) {
|
|
123
96
|
const authorLegacy = getFrontMatterAuthorLegacy(params);
|
|
124
97
|
const authors = getFrontMatterAuthors(params);
|
|
125
|
-
const updatedAuthors = fixAuthorImageBaseURL(authors, params);
|
|
126
98
|
if (authorLegacy) {
|
|
127
99
|
// Technically, we could allow mixing legacy/authors front matter, but do we
|
|
128
100
|
// really want to?
|
|
129
|
-
if (
|
|
101
|
+
if (authors.length > 0) {
|
|
130
102
|
throw new Error(`To declare blog post authors, use the 'authors' front matter in priority.
|
|
131
103
|
Don't mix 'authors' with other existing 'author_*' front matter. Choose one or the other, not both at the same time.`);
|
|
132
104
|
}
|
|
133
105
|
return [authorLegacy];
|
|
134
106
|
}
|
|
135
|
-
return
|
|
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)));
|
|
136
115
|
}
|
|
137
|
-
exports.getBlogPostAuthors = getBlogPostAuthors;
|
|
@@ -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
|
+
}
|
|
@@ -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;
|