@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/lib/authors.d.ts +3 -1
- package/lib/authors.js +14 -6
- package/lib/blogUtils.d.ts +5 -3
- package/lib/blogUtils.js +21 -19
- package/lib/feed.d.ts +3 -3
- package/lib/feed.js +16 -17
- package/lib/{blogFrontMatter.d.ts → frontMatter.d.ts} +3 -1
- package/lib/{blogFrontMatter.js → frontMatter.js} +0 -0
- package/lib/index.d.ts +3 -4
- package/lib/index.js +50 -58
- package/lib/markdownLoader.js +1 -1
- package/lib/options.d.ts +10 -0
- package/lib/{pluginOptionSchema.js → options.js} +9 -4
- package/lib/remark/footnoteIDFixer.d.ts +14 -0
- package/lib/remark/footnoteIDFixer.js +29 -0
- package/lib/translations.d.ts +4 -5
- package/lib/translations.js +4 -4
- package/lib/types.d.ts +4 -73
- package/package.json +13 -12
- package/src/authors.ts +29 -17
- package/src/blogUtils.ts +30 -22
- package/src/deps.d.ts +1 -1
- package/src/feed.ts +53 -56
- package/src/{blogFrontMatter.ts → frontMatter.ts} +3 -3
- package/src/index.ts +74 -98
- package/src/markdownLoader.ts +1 -1
- package/src/{pluginOptionSchema.ts → options.ts} +16 -4
- package/src/plugin-content-blog.d.ts +408 -97
- package/src/remark/footnoteIDFixer.ts +29 -0
- package/src/translations.ts +14 -9
- package/src/types.ts +2 -94
- package/lib/pluginOptionSchema.d.ts +0 -10
package/lib/authors.d.ts
CHANGED
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import type { BlogContentPaths } from './types';
|
|
8
8
|
import type { Author, BlogPostFrontMatter } from '@docusaurus/plugin-content-blog';
|
|
9
|
-
export declare type AuthorsMap =
|
|
9
|
+
export declare type AuthorsMap = {
|
|
10
|
+
[authorKey: string]: Author;
|
|
11
|
+
};
|
|
10
12
|
export declare function validateAuthorsMap(content: unknown): AuthorsMap;
|
|
11
13
|
export declare function getAuthorsMap(params: {
|
|
12
14
|
authorsMapPath: string;
|
package/lib/authors.js
CHANGED
|
@@ -9,16 +9,25 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
9
9
|
exports.getBlogPostAuthors = exports.getAuthorsMap = exports.validateAuthorsMap = void 0;
|
|
10
10
|
const utils_1 = require("@docusaurus/utils");
|
|
11
11
|
const utils_validation_1 = require("@docusaurus/utils-validation");
|
|
12
|
-
const AuthorsMapSchema = utils_validation_1.Joi.object()
|
|
12
|
+
const AuthorsMapSchema = utils_validation_1.Joi.object()
|
|
13
|
+
.pattern(utils_validation_1.Joi.string(), utils_validation_1.Joi.object({
|
|
13
14
|
name: utils_validation_1.Joi.string(),
|
|
14
15
|
url: utils_validation_1.URISchema,
|
|
15
16
|
imageURL: utils_validation_1.URISchema,
|
|
16
17
|
title: utils_validation_1.Joi.string(),
|
|
18
|
+
email: utils_validation_1.Joi.string(),
|
|
17
19
|
})
|
|
18
20
|
.rename('image_url', 'imageURL')
|
|
19
21
|
.or('name', 'imageURL')
|
|
20
22
|
.unknown()
|
|
21
|
-
.required()
|
|
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
|
+
});
|
|
22
31
|
function validateAuthorsMap(content) {
|
|
23
32
|
return utils_validation_1.Joi.attempt(content, AuthorsMapSchema);
|
|
24
33
|
}
|
|
@@ -34,11 +43,10 @@ exports.getAuthorsMap = getAuthorsMap;
|
|
|
34
43
|
// Legacy v1/early-v2 front matter fields
|
|
35
44
|
// We may want to deprecate those in favor of using only frontMatter.authors
|
|
36
45
|
function getFrontMatterAuthorLegacy(frontMatter) {
|
|
37
|
-
var _a, _b, _c;
|
|
38
46
|
const name = frontMatter.author;
|
|
39
|
-
const title =
|
|
40
|
-
const url =
|
|
41
|
-
const imageURL =
|
|
47
|
+
const title = frontMatter.author_title ?? frontMatter.authorTitle;
|
|
48
|
+
const url = frontMatter.author_url ?? frontMatter.authorURL;
|
|
49
|
+
const imageURL = frontMatter.author_image_url ?? frontMatter.authorImageURL;
|
|
42
50
|
if (name || title || url || imageURL) {
|
|
43
51
|
return {
|
|
44
52
|
name,
|
package/lib/blogUtils.d.ts
CHANGED
|
@@ -4,11 +4,13 @@
|
|
|
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 {
|
|
7
|
+
import type { BlogContentPaths, BlogMarkdownLoaderOptions } from './types';
|
|
8
8
|
import type { LoadContext } from '@docusaurus/types';
|
|
9
|
-
import type { PluginOptions } from '@docusaurus/plugin-content-blog';
|
|
9
|
+
import type { PluginOptions, BlogPost, BlogTags, BlogPaginated } from '@docusaurus/plugin-content-blog';
|
|
10
10
|
export declare function truncate(fileString: string, truncateMarker: RegExp): string;
|
|
11
|
-
export declare function getSourceToPermalink(blogPosts: BlogPost[]):
|
|
11
|
+
export declare function getSourceToPermalink(blogPosts: BlogPost[]): {
|
|
12
|
+
[aliasedPath: string]: string;
|
|
13
|
+
};
|
|
12
14
|
export declare function paginateBlogPosts({ blogPosts, basePageUrl, blogTitle, blogDescription, postsPerPageOption, }: {
|
|
13
15
|
blogPosts: BlogPost[];
|
|
14
16
|
basePageUrl: string;
|
package/lib/blogUtils.js
CHANGED
|
@@ -8,14 +8,14 @@
|
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
9
|
exports.linkify = exports.generateBlogPosts = exports.parseBlogFileName = exports.getBlogTags = exports.paginateBlogPosts = exports.getSourceToPermalink = exports.truncate = void 0;
|
|
10
10
|
const tslib_1 = require("tslib");
|
|
11
|
-
const fs_extra_1 =
|
|
12
|
-
const path_1 =
|
|
13
|
-
const reading_time_1 =
|
|
14
|
-
const lodash_1 =
|
|
11
|
+
const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
|
|
12
|
+
const path_1 = tslib_1.__importDefault(require("path"));
|
|
13
|
+
const reading_time_1 = tslib_1.__importDefault(require("reading-time"));
|
|
14
|
+
const lodash_1 = tslib_1.__importDefault(require("lodash"));
|
|
15
15
|
const utils_1 = require("@docusaurus/utils");
|
|
16
|
-
const
|
|
16
|
+
const frontMatter_1 = require("./frontMatter");
|
|
17
17
|
const authors_1 = require("./authors");
|
|
18
|
-
const logger_1 =
|
|
18
|
+
const logger_1 = tslib_1.__importDefault(require("@docusaurus/logger"));
|
|
19
19
|
function truncate(fileString, truncateMarker) {
|
|
20
20
|
return fileString.split(truncateMarker, 1).shift();
|
|
21
21
|
}
|
|
@@ -30,7 +30,9 @@ function paginateBlogPosts({ blogPosts, basePageUrl, blogTitle, blogDescription,
|
|
|
30
30
|
const numberOfPages = Math.ceil(totalCount / postsPerPage);
|
|
31
31
|
const pages = [];
|
|
32
32
|
function permalink(page) {
|
|
33
|
-
return page > 0
|
|
33
|
+
return page > 0
|
|
34
|
+
? (0, utils_1.normalizeUrl)([basePageUrl, `page/${page + 1}`])
|
|
35
|
+
: basePageUrl;
|
|
34
36
|
}
|
|
35
37
|
for (let page = 0; page < numberOfPages; page += 1) {
|
|
36
38
|
pages.push({
|
|
@@ -43,8 +45,8 @@ function paginateBlogPosts({ blogPosts, basePageUrl, blogTitle, blogDescription,
|
|
|
43
45
|
postsPerPage,
|
|
44
46
|
totalPages: numberOfPages,
|
|
45
47
|
totalCount,
|
|
46
|
-
previousPage: page !== 0 ? permalink(page - 1) :
|
|
47
|
-
nextPage: page < numberOfPages - 1 ? permalink(page + 1) :
|
|
48
|
+
previousPage: page !== 0 ? permalink(page - 1) : undefined,
|
|
49
|
+
nextPage: page < numberOfPages - 1 ? permalink(page + 1) : undefined,
|
|
48
50
|
blogDescription,
|
|
49
51
|
blogTitle,
|
|
50
52
|
},
|
|
@@ -56,7 +58,7 @@ exports.paginateBlogPosts = paginateBlogPosts;
|
|
|
56
58
|
function getBlogTags({ blogPosts, ...params }) {
|
|
57
59
|
const groups = (0, utils_1.groupTaggedItems)(blogPosts, (blogPost) => blogPost.metadata.tags);
|
|
58
60
|
return lodash_1.default.mapValues(groups, ({ tag, items: tagBlogPosts }) => ({
|
|
59
|
-
|
|
61
|
+
label: tag.label,
|
|
60
62
|
items: tagBlogPosts.map((item) => item.id),
|
|
61
63
|
permalink: tag.permalink,
|
|
62
64
|
pages: paginateBlogPosts({
|
|
@@ -76,20 +78,21 @@ function parseBlogFileName(blogSourceRelative) {
|
|
|
76
78
|
const date = new Date(`${dateString}Z`);
|
|
77
79
|
const slugDate = dateString.replace(/-/g, '/');
|
|
78
80
|
const slug = `/${slugDate}/${folder}${text}`;
|
|
79
|
-
return { date, text, slug };
|
|
81
|
+
return { date, text: text, slug };
|
|
80
82
|
}
|
|
81
83
|
const text = blogSourceRelative.replace(/(?:\/index)?\.mdx?$/, '');
|
|
82
84
|
const slug = `/${text}`;
|
|
83
85
|
return { date: undefined, text, slug };
|
|
84
86
|
}
|
|
85
87
|
exports.parseBlogFileName = parseBlogFileName;
|
|
86
|
-
function formatBlogPostDate(locale, date) {
|
|
88
|
+
function formatBlogPostDate(locale, date, calendar) {
|
|
87
89
|
try {
|
|
88
90
|
return new Intl.DateTimeFormat(locale, {
|
|
89
91
|
day: 'numeric',
|
|
90
92
|
month: 'long',
|
|
91
93
|
year: 'numeric',
|
|
92
94
|
timeZone: 'UTC',
|
|
95
|
+
calendar,
|
|
93
96
|
}).format(date);
|
|
94
97
|
}
|
|
95
98
|
catch (err) {
|
|
@@ -105,7 +108,7 @@ async function parseBlogPostMarkdownFile(blogSourceAbsolute) {
|
|
|
105
108
|
});
|
|
106
109
|
return {
|
|
107
110
|
...result,
|
|
108
|
-
frontMatter: (0,
|
|
111
|
+
frontMatter: (0, frontMatter_1.validateBlogPostFrontMatter)(result.frontMatter),
|
|
109
112
|
};
|
|
110
113
|
}
|
|
111
114
|
catch (err) {
|
|
@@ -115,7 +118,6 @@ async function parseBlogPostMarkdownFile(blogSourceAbsolute) {
|
|
|
115
118
|
}
|
|
116
119
|
const defaultReadingTime = ({ content, options }) => (0, reading_time_1.default)(content, options).minutes;
|
|
117
120
|
async function processBlogSourceFile(blogSourceRelative, contentPaths, context, options, authorsMap) {
|
|
118
|
-
var _a, _b, _c, _d;
|
|
119
121
|
const { siteConfig: { baseUrl }, siteDir, i18n, } = context;
|
|
120
122
|
const { routeBasePath, tagsBasePath: tagsRouteBasePath, truncateMarker, showReadingTime, editUrl, } = options;
|
|
121
123
|
// Lookup in localized folder in priority
|
|
@@ -151,14 +153,14 @@ async function processBlogSourceFile(blogSourceRelative, contentPaths, context,
|
|
|
151
153
|
return result.date;
|
|
152
154
|
}
|
|
153
155
|
catch (err) {
|
|
154
|
-
logger_1.default.
|
|
156
|
+
logger_1.default.warn(err);
|
|
155
157
|
return (await fs_extra_1.default.stat(blogSourceAbsolute)).birthtime;
|
|
156
158
|
}
|
|
157
159
|
}
|
|
158
160
|
const date = await getDate();
|
|
159
|
-
const formattedDate = formatBlogPostDate(i18n.currentLocale, date);
|
|
160
|
-
const title =
|
|
161
|
-
const description =
|
|
161
|
+
const formattedDate = formatBlogPostDate(i18n.currentLocale, date, i18n.localeConfigs[i18n.currentLocale].calendar);
|
|
162
|
+
const title = frontMatter.title ?? contentTitle ?? parsedBlogFileName.text;
|
|
163
|
+
const description = frontMatter.description ?? excerpt ?? '';
|
|
162
164
|
const slug = frontMatter.slug || parsedBlogFileName.slug;
|
|
163
165
|
const permalink = (0, utils_1.normalizeUrl)([baseUrl, routeBasePath, slug]);
|
|
164
166
|
function getBlogEditUrl() {
|
|
@@ -208,7 +210,7 @@ async function processBlogSourceFile(blogSourceRelative, contentPaths, context,
|
|
|
208
210
|
defaultReadingTime,
|
|
209
211
|
})
|
|
210
212
|
: undefined,
|
|
211
|
-
truncated:
|
|
213
|
+
truncated: truncateMarker?.test(content) || false,
|
|
212
214
|
authors,
|
|
213
215
|
frontMatter,
|
|
214
216
|
},
|
package/lib/feed.d.ts
CHANGED
|
@@ -4,12 +4,12 @@
|
|
|
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 { BlogPost } from './types';
|
|
8
7
|
import type { DocusaurusConfig } from '@docusaurus/types';
|
|
9
|
-
import type { PluginOptions } from '@docusaurus/plugin-content-blog';
|
|
10
|
-
export declare function createBlogFeedFiles({ blogPosts, options, siteConfig, outDir, }: {
|
|
8
|
+
import type { PluginOptions, BlogPost } from '@docusaurus/plugin-content-blog';
|
|
9
|
+
export declare function createBlogFeedFiles({ blogPosts, options, siteConfig, outDir, locale, }: {
|
|
11
10
|
blogPosts: BlogPost[];
|
|
12
11
|
options: PluginOptions;
|
|
13
12
|
siteConfig: DocusaurusConfig;
|
|
14
13
|
outDir: string;
|
|
14
|
+
locale: string;
|
|
15
15
|
}): Promise<void>;
|
package/lib/feed.js
CHANGED
|
@@ -10,37 +10,35 @@ exports.createBlogFeedFiles = void 0;
|
|
|
10
10
|
const tslib_1 = require("tslib");
|
|
11
11
|
const feed_1 = require("feed");
|
|
12
12
|
const utils_1 = require("@docusaurus/utils");
|
|
13
|
-
const cheerio_1 =
|
|
14
|
-
const path_1 =
|
|
15
|
-
const fs_extra_1 =
|
|
13
|
+
const cheerio_1 = require("cheerio");
|
|
14
|
+
const path_1 = tslib_1.__importDefault(require("path"));
|
|
15
|
+
const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
|
|
16
16
|
const utils_common_1 = require("@docusaurus/utils-common");
|
|
17
|
-
async function generateBlogFeed({ blogPosts, options, siteConfig, outDir, }) {
|
|
17
|
+
async function generateBlogFeed({ blogPosts, options, siteConfig, outDir, locale, }) {
|
|
18
18
|
if (!blogPosts.length) {
|
|
19
19
|
return null;
|
|
20
20
|
}
|
|
21
21
|
const { feedOptions, routeBasePath } = options;
|
|
22
22
|
const { url: siteUrl, baseUrl, title, favicon } = siteConfig;
|
|
23
23
|
const blogBaseUrl = (0, utils_1.normalizeUrl)([siteUrl, baseUrl, routeBasePath]);
|
|
24
|
-
const updated = blogPosts[0]
|
|
24
|
+
const updated = blogPosts[0]?.metadata.date;
|
|
25
25
|
const feed = new feed_1.Feed({
|
|
26
26
|
id: blogBaseUrl,
|
|
27
|
-
title: feedOptions.title
|
|
27
|
+
title: feedOptions.title ?? `${title} Blog`,
|
|
28
28
|
updated,
|
|
29
|
-
language: feedOptions.language,
|
|
29
|
+
language: feedOptions.language ?? locale,
|
|
30
30
|
link: blogBaseUrl,
|
|
31
|
-
description: feedOptions.description
|
|
31
|
+
description: feedOptions.description ?? `${siteConfig.title} Blog`,
|
|
32
32
|
favicon: favicon ? (0, utils_1.normalizeUrl)([siteUrl, baseUrl, favicon]) : undefined,
|
|
33
33
|
copyright: feedOptions.copyright,
|
|
34
34
|
});
|
|
35
35
|
function toFeedAuthor(author) {
|
|
36
|
-
|
|
37
|
-
// RSS feed requires email to render authors
|
|
38
|
-
return { name: author.name, link: author.url };
|
|
36
|
+
return { name: author.name, link: author.url, email: author.email };
|
|
39
37
|
}
|
|
40
|
-
await (
|
|
38
|
+
await Promise.all(blogPosts.map(async (post) => {
|
|
41
39
|
const { id, metadata: { title: metadataTitle, permalink, date, description, authors, tags, }, } = post;
|
|
42
40
|
const content = await (0, utils_1.readOutputHTMLFile)(permalink.replace(siteConfig.baseUrl, ''), outDir, siteConfig.trailingSlash);
|
|
43
|
-
const $ = cheerio_1.
|
|
41
|
+
const $ = (0, cheerio_1.load)(content);
|
|
44
42
|
const feedItem = {
|
|
45
43
|
title: metadataTitle,
|
|
46
44
|
id,
|
|
@@ -57,8 +55,8 @@ async function generateBlogFeed({ blogPosts, options, siteConfig, outDir, }) {
|
|
|
57
55
|
if (feedItemAuthors.length > 0) {
|
|
58
56
|
feedItem.author = feedItemAuthors;
|
|
59
57
|
}
|
|
60
|
-
|
|
61
|
-
});
|
|
58
|
+
return feedItem;
|
|
59
|
+
})).then((items) => items.forEach(feed.addItem));
|
|
62
60
|
return feed;
|
|
63
61
|
}
|
|
64
62
|
async function createBlogFeedFile({ feed, feedType, generatePath, }) {
|
|
@@ -75,18 +73,19 @@ async function createBlogFeedFile({ feed, feedType, generatePath, }) {
|
|
|
75
73
|
}
|
|
76
74
|
})();
|
|
77
75
|
try {
|
|
78
|
-
await fs_extra_1.default.outputFile(
|
|
76
|
+
await fs_extra_1.default.outputFile(path_1.default.join(generatePath, feedPath), feedContent);
|
|
79
77
|
}
|
|
80
78
|
catch (err) {
|
|
81
79
|
throw new Error(`Generating ${feedType} feed failed: ${err}.`);
|
|
82
80
|
}
|
|
83
81
|
}
|
|
84
|
-
async function createBlogFeedFiles({ blogPosts, options, siteConfig, outDir, }) {
|
|
82
|
+
async function createBlogFeedFiles({ blogPosts, options, siteConfig, outDir, locale, }) {
|
|
85
83
|
const feed = await generateBlogFeed({
|
|
86
84
|
blogPosts,
|
|
87
85
|
options,
|
|
88
86
|
siteConfig,
|
|
89
87
|
outDir,
|
|
88
|
+
locale,
|
|
90
89
|
});
|
|
91
90
|
const feedTypes = options.feedOptions.type;
|
|
92
91
|
if (!feed || !feedTypes) {
|
|
@@ -5,4 +5,6 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
import type { BlogPostFrontMatter } from '@docusaurus/plugin-content-blog';
|
|
8
|
-
export declare function validateBlogPostFrontMatter(frontMatter:
|
|
8
|
+
export declare function validateBlogPostFrontMatter(frontMatter: {
|
|
9
|
+
[key: string]: unknown;
|
|
10
|
+
}): BlogPostFrontMatter;
|
|
File without changes
|
package/lib/index.d.ts
CHANGED
|
@@ -4,8 +4,7 @@
|
|
|
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 {
|
|
8
|
-
import type {
|
|
9
|
-
import type { PluginOptions } from '@docusaurus/plugin-content-blog';
|
|
7
|
+
import type { LoadContext, Plugin } from '@docusaurus/types';
|
|
8
|
+
import type { PluginOptions, BlogContent } from '@docusaurus/plugin-content-blog';
|
|
10
9
|
export default function pluginContentBlog(context: LoadContext, options: PluginOptions): Promise<Plugin<BlogContent>>;
|
|
11
|
-
export
|
|
10
|
+
export { validateOptions } from './options';
|
package/lib/index.js
CHANGED
|
@@ -8,15 +8,14 @@
|
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
9
|
exports.validateOptions = void 0;
|
|
10
10
|
const tslib_1 = require("tslib");
|
|
11
|
-
const path_1 =
|
|
12
|
-
const remark_admonitions_1 =
|
|
11
|
+
const path_1 = tslib_1.__importDefault(require("path"));
|
|
12
|
+
const remark_admonitions_1 = tslib_1.__importDefault(require("remark-admonitions"));
|
|
13
|
+
const footnoteIDFixer_1 = tslib_1.__importDefault(require("./remark/footnoteIDFixer"));
|
|
13
14
|
const utils_1 = require("@docusaurus/utils");
|
|
14
15
|
const translations_1 = require("./translations");
|
|
15
|
-
const pluginOptionSchema_1 = require("./pluginOptionSchema");
|
|
16
16
|
const blogUtils_1 = require("./blogUtils");
|
|
17
17
|
const feed_1 = require("./feed");
|
|
18
18
|
async function pluginContentBlog(context, options) {
|
|
19
|
-
var _a;
|
|
20
19
|
if (options.admonitions) {
|
|
21
20
|
options.remarkPlugins = options.remarkPlugins.concat([
|
|
22
21
|
[remark_admonitions_1.default, options.admonitions],
|
|
@@ -33,7 +32,7 @@ async function pluginContentBlog(context, options) {
|
|
|
33
32
|
pluginId: options.id,
|
|
34
33
|
}),
|
|
35
34
|
};
|
|
36
|
-
const pluginId =
|
|
35
|
+
const pluginId = options.id ?? utils_1.DEFAULT_PLUGIN_ID;
|
|
37
36
|
const pluginDataDirRoot = path_1.default.join(generatedFilesDir, 'docusaurus-plugin-content-blog');
|
|
38
37
|
const dataDir = path_1.default.join(pluginDataDirRoot, pluginId);
|
|
39
38
|
const aliasedSource = (source) => `~blog/${(0, utils_1.posixPath)(path_1.default.relative(pluginDataDirRoot, source))}`;
|
|
@@ -48,12 +47,14 @@ async function pluginContentBlog(context, options) {
|
|
|
48
47
|
const contentMarkdownGlobs = (0, utils_1.getContentPathList)(contentPaths).flatMap((contentPath) => include.map((pattern) => `${contentPath}/${pattern}`));
|
|
49
48
|
return [authorsMapFilePath, ...contentMarkdownGlobs].filter(Boolean);
|
|
50
49
|
},
|
|
51
|
-
|
|
50
|
+
getTranslationFiles() {
|
|
52
51
|
return (0, translations_1.getTranslationFiles)(options);
|
|
53
52
|
},
|
|
54
53
|
// Fetches blog contents and returns metadata for the necessary routes.
|
|
55
54
|
async loadContent() {
|
|
56
55
|
const { postsPerPage: postsPerPageOption, routeBasePath, tagsBasePath, blogDescription, blogTitle, blogSidebarTitle, } = options;
|
|
56
|
+
const baseBlogUrl = (0, utils_1.normalizeUrl)([baseUrl, routeBasePath]);
|
|
57
|
+
const blogTagsListPath = (0, utils_1.normalizeUrl)([baseBlogUrl, tagsBasePath]);
|
|
57
58
|
const blogPosts = await (0, blogUtils_1.generateBlogPosts)(contentPaths, context, options);
|
|
58
59
|
if (!blogPosts.length) {
|
|
59
60
|
return {
|
|
@@ -61,7 +62,7 @@ async function pluginContentBlog(context, options) {
|
|
|
61
62
|
blogPosts: [],
|
|
62
63
|
blogListPaginated: [],
|
|
63
64
|
blogTags: {},
|
|
64
|
-
blogTagsListPath
|
|
65
|
+
blogTagsListPath,
|
|
65
66
|
blogTagsPaginated: [],
|
|
66
67
|
};
|
|
67
68
|
}
|
|
@@ -82,7 +83,6 @@ async function pluginContentBlog(context, options) {
|
|
|
82
83
|
};
|
|
83
84
|
}
|
|
84
85
|
});
|
|
85
|
-
const baseBlogUrl = (0, utils_1.normalizeUrl)([baseUrl, routeBasePath]);
|
|
86
86
|
const blogListPaginated = (0, blogUtils_1.paginateBlogPosts)({
|
|
87
87
|
blogPosts,
|
|
88
88
|
blogTitle,
|
|
@@ -96,8 +96,6 @@ async function pluginContentBlog(context, options) {
|
|
|
96
96
|
blogDescription,
|
|
97
97
|
blogTitle,
|
|
98
98
|
});
|
|
99
|
-
const tagsPath = (0, utils_1.normalizeUrl)([baseBlogUrl, tagsBasePath]);
|
|
100
|
-
const blogTagsListPath = Object.keys(blogTags).length > 0 ? tagsPath : null;
|
|
101
99
|
return {
|
|
102
100
|
blogSidebarTitle,
|
|
103
101
|
blogPosts,
|
|
@@ -117,13 +115,13 @@ async function pluginContentBlog(context, options) {
|
|
|
117
115
|
const sidebarBlogPosts = options.blogSidebarCount === 'ALL'
|
|
118
116
|
? blogPosts
|
|
119
117
|
: blogPosts.slice(0, options.blogSidebarCount);
|
|
120
|
-
if (archiveBasePath) {
|
|
118
|
+
if (archiveBasePath && blogPosts.length) {
|
|
121
119
|
const archiveUrl = (0, utils_1.normalizeUrl)([
|
|
122
120
|
baseUrl,
|
|
123
121
|
routeBasePath,
|
|
124
122
|
archiveBasePath,
|
|
125
123
|
]);
|
|
126
|
-
//
|
|
124
|
+
// Create a blog archive route
|
|
127
125
|
const archiveProp = await createData(`${(0, utils_1.docuHash)(archiveUrl)}.json`, JSON.stringify({ blogPosts }, null, 2));
|
|
128
126
|
addRoute({
|
|
129
127
|
path: archiveUrl,
|
|
@@ -174,10 +172,7 @@ async function pluginContentBlog(context, options) {
|
|
|
174
172
|
exact: true,
|
|
175
173
|
modules: {
|
|
176
174
|
sidebar: aliasedSource(sidebarProp),
|
|
177
|
-
items: items.map((postID) =>
|
|
178
|
-
// To tell routes.js this is an import and not a nested object
|
|
179
|
-
// to recurse.
|
|
180
|
-
({
|
|
175
|
+
items: items.map((postID) => ({
|
|
181
176
|
content: {
|
|
182
177
|
__import: true,
|
|
183
178
|
path: blogItemsToMetadata[postID].source,
|
|
@@ -190,24 +185,37 @@ async function pluginContentBlog(context, options) {
|
|
|
190
185
|
},
|
|
191
186
|
});
|
|
192
187
|
}));
|
|
193
|
-
// Tags.
|
|
194
|
-
if (
|
|
188
|
+
// Tags. This is the last part so we early-return if there are no tags.
|
|
189
|
+
if (Object.keys(blogTags).length === 0) {
|
|
195
190
|
return;
|
|
196
191
|
}
|
|
197
|
-
|
|
198
|
-
const
|
|
199
|
-
|
|
200
|
-
slug: tagKey,
|
|
201
|
-
name: tag.name,
|
|
202
|
-
count: tag.items.length,
|
|
192
|
+
async function createTagsListPage() {
|
|
193
|
+
const tagsProp = Object.values(blogTags).map((tag) => ({
|
|
194
|
+
label: tag.label,
|
|
203
195
|
permalink: tag.permalink,
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
196
|
+
count: tag.items.length,
|
|
197
|
+
}));
|
|
198
|
+
const tagsPropPath = await createData(`${(0, utils_1.docuHash)(`${blogTagsListPath}-tags`)}.json`, JSON.stringify(tagsProp, null, 2));
|
|
199
|
+
addRoute({
|
|
200
|
+
path: blogTagsListPath,
|
|
201
|
+
component: blogTagsListComponent,
|
|
202
|
+
exact: true,
|
|
203
|
+
modules: {
|
|
204
|
+
sidebar: aliasedSource(sidebarProp),
|
|
205
|
+
tags: aliasedSource(tagsPropPath),
|
|
206
|
+
},
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
async function createTagPostsListPage(tag) {
|
|
208
210
|
await Promise.all(tag.pages.map(async (blogPaginated) => {
|
|
209
211
|
const { metadata, items } = blogPaginated;
|
|
210
|
-
const
|
|
212
|
+
const tagProp = {
|
|
213
|
+
label: tag.label,
|
|
214
|
+
permalink: tag.permalink,
|
|
215
|
+
allTagsPath: blogTagsListPath,
|
|
216
|
+
count: tag.items.length,
|
|
217
|
+
};
|
|
218
|
+
const tagPropPath = await createData(`${(0, utils_1.docuHash)(metadata.permalink)}.json`, JSON.stringify(tagProp, null, 2));
|
|
211
219
|
const listMetadataPath = await createData(`${(0, utils_1.docuHash)(metadata.permalink)}-list.json`, JSON.stringify(metadata, null, 2));
|
|
212
220
|
addRoute({
|
|
213
221
|
path: metadata.permalink,
|
|
@@ -227,26 +235,14 @@ async function pluginContentBlog(context, options) {
|
|
|
227
235
|
},
|
|
228
236
|
};
|
|
229
237
|
}),
|
|
230
|
-
|
|
238
|
+
tag: aliasedSource(tagPropPath),
|
|
231
239
|
listMetadata: aliasedSource(listMetadataPath),
|
|
232
240
|
},
|
|
233
241
|
});
|
|
234
242
|
}));
|
|
235
243
|
}
|
|
236
|
-
await
|
|
237
|
-
|
|
238
|
-
if (Object.keys(blogTags).length > 0) {
|
|
239
|
-
const tagsListPath = await createData(`${(0, utils_1.docuHash)(`${blogTagsListPath}-tags`)}.json`, JSON.stringify(tagsModule, null, 2));
|
|
240
|
-
addRoute({
|
|
241
|
-
path: blogTagsListPath,
|
|
242
|
-
component: blogTagsListComponent,
|
|
243
|
-
exact: true,
|
|
244
|
-
modules: {
|
|
245
|
-
sidebar: aliasedSource(sidebarProp),
|
|
246
|
-
tags: aliasedSource(tagsListPath),
|
|
247
|
-
},
|
|
248
|
-
});
|
|
249
|
-
}
|
|
244
|
+
await createTagsListPage();
|
|
245
|
+
await Promise.all(Object.values(blogTags).map(createTagPostsListPage));
|
|
250
246
|
},
|
|
251
247
|
translateContent({ content, translationFiles }) {
|
|
252
248
|
return (0, translations_1.translateContent)(content, translationFiles);
|
|
@@ -286,7 +282,10 @@ async function pluginContentBlog(context, options) {
|
|
|
286
282
|
options: {
|
|
287
283
|
remarkPlugins,
|
|
288
284
|
rehypePlugins,
|
|
289
|
-
beforeDefaultRemarkPlugins
|
|
285
|
+
beforeDefaultRemarkPlugins: [
|
|
286
|
+
footnoteIDFixer_1.default,
|
|
287
|
+
...beforeDefaultRemarkPlugins,
|
|
288
|
+
],
|
|
290
289
|
beforeDefaultRehypePlugins,
|
|
291
290
|
staticDirs: siteConfig.staticDirectories.map((dir) => path_1.default.resolve(siteDir, dir)),
|
|
292
291
|
siteDir,
|
|
@@ -331,18 +330,18 @@ async function pluginContentBlog(context, options) {
|
|
|
331
330
|
options,
|
|
332
331
|
outDir,
|
|
333
332
|
siteConfig,
|
|
333
|
+
locale: currentLocale,
|
|
334
334
|
});
|
|
335
335
|
},
|
|
336
336
|
injectHtmlTags({ content }) {
|
|
337
|
-
var _a, _b;
|
|
338
337
|
if (!content.blogPosts.length) {
|
|
339
338
|
return {};
|
|
340
339
|
}
|
|
341
|
-
if (!
|
|
340
|
+
if (!options.feedOptions?.type) {
|
|
342
341
|
return {};
|
|
343
342
|
}
|
|
344
343
|
const feedTypes = options.feedOptions.type;
|
|
345
|
-
const feedTitle =
|
|
344
|
+
const feedTitle = options.feedOptions.title ?? context.siteConfig.title;
|
|
346
345
|
const feedsConfig = {
|
|
347
346
|
rss: {
|
|
348
347
|
type: 'application/rss+xml',
|
|
@@ -362,11 +361,7 @@ async function pluginContentBlog(context, options) {
|
|
|
362
361
|
};
|
|
363
362
|
const headTags = [];
|
|
364
363
|
feedTypes.forEach((feedType) => {
|
|
365
|
-
const
|
|
366
|
-
if (!feedsConfig) {
|
|
367
|
-
return;
|
|
368
|
-
}
|
|
369
|
-
const { type, path: feedConfigPath, title: feedConfigTitle } = feedConfig;
|
|
364
|
+
const { type, path: feedConfigPath, title: feedConfigTitle, } = feedsConfig[feedType];
|
|
370
365
|
headTags.push({
|
|
371
366
|
tagName: 'link',
|
|
372
367
|
attributes: {
|
|
@@ -388,8 +383,5 @@ async function pluginContentBlog(context, options) {
|
|
|
388
383
|
};
|
|
389
384
|
}
|
|
390
385
|
exports.default = pluginContentBlog;
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
return validatedOptions;
|
|
394
|
-
}
|
|
395
|
-
exports.validateOptions = validateOptions;
|
|
386
|
+
var options_1 = require("./options");
|
|
387
|
+
Object.defineProperty(exports, "validateOptions", { enumerable: true, get: function () { return options_1.validateOptions; } });
|
package/lib/markdownLoader.js
CHANGED
|
@@ -25,6 +25,6 @@ function markdownLoader(source) {
|
|
|
25
25
|
if (truncated) {
|
|
26
26
|
finalContent = (0, blogUtils_1.truncate)(finalContent, markdownLoaderOptions.truncateMarker);
|
|
27
27
|
}
|
|
28
|
-
return callback
|
|
28
|
+
return callback?.(null, finalContent);
|
|
29
29
|
}
|
|
30
30
|
exports.default = markdownLoader;
|
package/lib/options.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
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 { PluginOptions, Options } from '@docusaurus/plugin-content-blog';
|
|
8
|
+
import type { OptionValidationContext } from '@docusaurus/types';
|
|
9
|
+
export declare const DEFAULT_OPTIONS: PluginOptions;
|
|
10
|
+
export declare function validateOptions({ validate, options, }: OptionValidationContext<Options, PluginOptions>): PluginOptions;
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* LICENSE file in the root directory of this source tree.
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.
|
|
9
|
+
exports.validateOptions = exports.DEFAULT_OPTIONS = void 0;
|
|
10
10
|
const utils_validation_1 = require("@docusaurus/utils-validation");
|
|
11
11
|
const utils_1 = require("@docusaurus/utils");
|
|
12
12
|
exports.DEFAULT_OPTIONS = {
|
|
@@ -39,7 +39,7 @@ exports.DEFAULT_OPTIONS = {
|
|
|
39
39
|
readingTime: ({ content, defaultReadingTime }) => defaultReadingTime({ content }),
|
|
40
40
|
sortPosts: 'descending',
|
|
41
41
|
};
|
|
42
|
-
|
|
42
|
+
const PluginOptionSchema = utils_validation_1.Joi.object({
|
|
43
43
|
path: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.path),
|
|
44
44
|
archiveBasePath: utils_validation_1.Joi.string()
|
|
45
45
|
.default(exports.DEFAULT_OPTIONS.archiveBasePath)
|
|
@@ -85,7 +85,7 @@ exports.PluginOptionSchema = utils_validation_1.Joi.object({
|
|
|
85
85
|
.default(exports.DEFAULT_OPTIONS.feedOptions.type),
|
|
86
86
|
title: utils_validation_1.Joi.string().allow(''),
|
|
87
87
|
description: utils_validation_1.Joi.string().allow(''),
|
|
88
|
-
//
|
|
88
|
+
// Only add default value when user actually wants a feed (type is not null)
|
|
89
89
|
copyright: utils_validation_1.Joi.when('type', {
|
|
90
90
|
is: utils_validation_1.Joi.any().valid(null),
|
|
91
91
|
then: utils_validation_1.Joi.string().optional(),
|
|
@@ -100,4 +100,9 @@ exports.PluginOptionSchema = utils_validation_1.Joi.object({
|
|
|
100
100
|
sortPosts: utils_validation_1.Joi.string()
|
|
101
101
|
.valid('descending', 'ascending')
|
|
102
102
|
.default(exports.DEFAULT_OPTIONS.sortPosts),
|
|
103
|
-
});
|
|
103
|
+
}).default(exports.DEFAULT_OPTIONS);
|
|
104
|
+
function validateOptions({ validate, options, }) {
|
|
105
|
+
const validatedOptions = validate(PluginOptionSchema, options);
|
|
106
|
+
return validatedOptions;
|
|
107
|
+
}
|
|
108
|
+
exports.validateOptions = validateOptions;
|
|
@@ -0,0 +1,14 @@
|
|
|
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 { Transformer } from 'unified';
|
|
8
|
+
/**
|
|
9
|
+
* In the blog list view, each post will be compiled separately. However, they
|
|
10
|
+
* may use the same footnote IDs. This leads to duplicated DOM IDs and inability
|
|
11
|
+
* to navigate to footnote references. This plugin fixes it by appending a
|
|
12
|
+
* unique hash to each reference/definition.
|
|
13
|
+
*/
|
|
14
|
+
export default function plugin(): Transformer;
|