@docusaurus/plugin-content-blog 2.4.0 → 3.0.0-alpha.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/lib/authors.d.ts +2 -2
- package/lib/blogUtils.d.ts +3 -2
- package/lib/blogUtils.js +30 -16
- package/lib/feed.d.ts +1 -1
- package/lib/feed.js +7 -1
- package/lib/frontMatter.js +4 -3
- package/lib/index.js +12 -19
- package/lib/options.js +2 -5
- package/lib/props.d.ts +15 -0
- package/lib/props.js +23 -0
- package/lib/types.d.ts +3 -3
- package/package.json +14 -14
- package/src/blogUtils.ts +47 -28
- package/src/feed.ts +10 -1
- package/src/frontMatter.ts +7 -5
- package/src/index.ts +13 -23
- package/src/options.ts +3 -5
- package/src/plugin-content-blog.d.ts +16 -1
- package/src/props.ts +34 -0
- package/src/remark/footnoteIDFixer.ts +1 -0
package/lib/authors.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import type { BlogContentPaths } from './types';
|
|
8
8
|
import type { Author, BlogPostFrontMatter } from '@docusaurus/plugin-content-blog';
|
|
9
|
-
export
|
|
9
|
+
export type AuthorsMap = {
|
|
10
10
|
[authorKey: string]: Author;
|
|
11
11
|
};
|
|
12
12
|
export declare function validateAuthorsMap(content: unknown): AuthorsMap;
|
|
@@ -14,7 +14,7 @@ export declare function getAuthorsMap(params: {
|
|
|
14
14
|
authorsMapPath: string;
|
|
15
15
|
contentPaths: BlogContentPaths;
|
|
16
16
|
}): Promise<AuthorsMap | undefined>;
|
|
17
|
-
|
|
17
|
+
type AuthorsParam = {
|
|
18
18
|
frontMatter: BlogPostFrontMatter;
|
|
19
19
|
authorsMap: AuthorsMap | undefined;
|
|
20
20
|
};
|
package/lib/blogUtils.d.ts
CHANGED
|
@@ -18,20 +18,21 @@ export declare function paginateBlogPosts({ blogPosts, basePageUrl, blogTitle, b
|
|
|
18
18
|
blogDescription: string;
|
|
19
19
|
postsPerPageOption: number | 'ALL';
|
|
20
20
|
}): BlogPaginated[];
|
|
21
|
+
export declare function shouldBeListed(blogPost: BlogPost): boolean;
|
|
21
22
|
export declare function getBlogTags({ blogPosts, ...params }: {
|
|
22
23
|
blogPosts: BlogPost[];
|
|
23
24
|
blogTitle: string;
|
|
24
25
|
blogDescription: string;
|
|
25
26
|
postsPerPageOption: number | 'ALL';
|
|
26
27
|
}): BlogTags;
|
|
27
|
-
|
|
28
|
+
type ParsedBlogFileName = {
|
|
28
29
|
date: Date | undefined;
|
|
29
30
|
text: string;
|
|
30
31
|
slug: string;
|
|
31
32
|
};
|
|
32
33
|
export declare function parseBlogFileName(blogSourceRelative: string): ParsedBlogFileName;
|
|
33
34
|
export declare function generateBlogPosts(contentPaths: BlogContentPaths, context: LoadContext, options: PluginOptions): Promise<BlogPost[]>;
|
|
34
|
-
export
|
|
35
|
+
export type LinkifyParams = {
|
|
35
36
|
filePath: string;
|
|
36
37
|
fileString: string;
|
|
37
38
|
} & Pick<BlogMarkdownLoaderOptions, 'sourceToPermalink' | 'siteDir' | 'contentPaths' | 'onBrokenMarkdownLink'>;
|
package/lib/blogUtils.js
CHANGED
|
@@ -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.linkify = exports.generateBlogPosts = exports.parseBlogFileName = exports.getBlogTags = exports.paginateBlogPosts = exports.getSourceToPermalink = exports.truncate = void 0;
|
|
9
|
+
exports.linkify = exports.generateBlogPosts = exports.parseBlogFileName = exports.getBlogTags = exports.shouldBeListed = exports.paginateBlogPosts = exports.getSourceToPermalink = exports.truncate = void 0;
|
|
10
10
|
const tslib_1 = require("tslib");
|
|
11
11
|
const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
|
|
12
12
|
const path_1 = tslib_1.__importDefault(require("path"));
|
|
@@ -55,18 +55,29 @@ function paginateBlogPosts({ blogPosts, basePageUrl, blogTitle, blogDescription,
|
|
|
55
55
|
return pages;
|
|
56
56
|
}
|
|
57
57
|
exports.paginateBlogPosts = paginateBlogPosts;
|
|
58
|
+
function shouldBeListed(blogPost) {
|
|
59
|
+
return !blogPost.metadata.unlisted;
|
|
60
|
+
}
|
|
61
|
+
exports.shouldBeListed = shouldBeListed;
|
|
58
62
|
function getBlogTags({ blogPosts, ...params }) {
|
|
59
63
|
const groups = (0, utils_1.groupTaggedItems)(blogPosts, (blogPost) => blogPost.metadata.tags);
|
|
60
|
-
return lodash_1.default.mapValues(groups, ({ tag, items: tagBlogPosts }) =>
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
64
|
+
return lodash_1.default.mapValues(groups, ({ tag, items: tagBlogPosts }) => {
|
|
65
|
+
const tagVisibility = (0, utils_1.getTagVisibility)({
|
|
66
|
+
items: tagBlogPosts,
|
|
67
|
+
isUnlisted: (item) => item.metadata.unlisted,
|
|
68
|
+
});
|
|
69
|
+
return {
|
|
70
|
+
label: tag.label,
|
|
71
|
+
items: tagVisibility.listedItems.map((item) => item.id),
|
|
72
|
+
permalink: tag.permalink,
|
|
73
|
+
pages: paginateBlogPosts({
|
|
74
|
+
blogPosts: tagVisibility.listedItems,
|
|
75
|
+
basePageUrl: tag.permalink,
|
|
76
|
+
...params,
|
|
77
|
+
}),
|
|
78
|
+
unlisted: tagVisibility.unlisted,
|
|
79
|
+
};
|
|
80
|
+
});
|
|
70
81
|
}
|
|
71
82
|
exports.getBlogTags = getBlogTags;
|
|
72
83
|
const DATE_FILENAME_REGEX = /^(?<folder>.*)(?<date>\d{4}[-/]\d{1,2}[-/]\d{1,2})[-/]?(?<text>.*?)(?:\/index)?.mdx?$/;
|
|
@@ -125,7 +136,9 @@ async function processBlogSourceFile(blogSourceRelative, contentPaths, context,
|
|
|
125
136
|
const blogSourceAbsolute = path_1.default.join(blogDirPath, blogSourceRelative);
|
|
126
137
|
const { frontMatter, content, contentTitle, excerpt } = await parseBlogPostMarkdownFile(blogSourceAbsolute);
|
|
127
138
|
const aliasedSource = (0, utils_1.aliasedSitePath)(blogSourceAbsolute, siteDir);
|
|
128
|
-
|
|
139
|
+
const draft = (0, utils_1.isDraft)({ frontMatter });
|
|
140
|
+
const unlisted = (0, utils_1.isUnlisted)({ frontMatter });
|
|
141
|
+
if (draft) {
|
|
129
142
|
return undefined;
|
|
130
143
|
}
|
|
131
144
|
if (frontMatter.id) {
|
|
@@ -213,6 +226,7 @@ async function processBlogSourceFile(blogSourceRelative, contentPaths, context,
|
|
|
213
226
|
hasTruncateMarker: truncateMarker.test(content),
|
|
214
227
|
authors,
|
|
215
228
|
frontMatter,
|
|
229
|
+
unlisted,
|
|
216
230
|
},
|
|
217
231
|
content,
|
|
218
232
|
};
|
|
@@ -230,15 +244,15 @@ async function generateBlogPosts(contentPaths, context, options) {
|
|
|
230
244
|
contentPaths,
|
|
231
245
|
authorsMapPath: options.authorsMapPath,
|
|
232
246
|
});
|
|
233
|
-
|
|
247
|
+
async function doProcessBlogSourceFile(blogSourceFile) {
|
|
234
248
|
try {
|
|
235
249
|
return await processBlogSourceFile(blogSourceFile, contentPaths, context, options, authorsMap);
|
|
236
250
|
}
|
|
237
251
|
catch (err) {
|
|
238
|
-
|
|
239
|
-
throw err;
|
|
252
|
+
throw new Error(`Processing of blog source file path=${blogSourceFile} failed.`, { cause: err });
|
|
240
253
|
}
|
|
241
|
-
}
|
|
254
|
+
}
|
|
255
|
+
const blogPosts = (await Promise.all(blogSourceFiles.map(doProcessBlogSourceFile))).filter(Boolean);
|
|
242
256
|
blogPosts.sort((a, b) => b.metadata.date.getTime() - a.metadata.date.getTime());
|
|
243
257
|
if (options.sortPosts === 'ascending') {
|
|
244
258
|
return blogPosts.reverse();
|
package/lib/feed.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import type { DocusaurusConfig } from '@docusaurus/types';
|
|
8
8
|
import type { PluginOptions, BlogPost } from '@docusaurus/plugin-content-blog';
|
|
9
|
-
export declare function createBlogFeedFiles({ blogPosts, options, siteConfig, outDir, locale, }: {
|
|
9
|
+
export declare function createBlogFeedFiles({ blogPosts: allBlogPosts, options, siteConfig, outDir, locale, }: {
|
|
10
10
|
blogPosts: BlogPost[];
|
|
11
11
|
options: PluginOptions;
|
|
12
12
|
siteConfig: DocusaurusConfig;
|
package/lib/feed.js
CHANGED
|
@@ -93,7 +93,13 @@ async function createBlogFeedFile({ feed, feedType, generatePath, }) {
|
|
|
93
93
|
throw err;
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
|
-
|
|
96
|
+
function shouldBeInFeed(blogPost) {
|
|
97
|
+
const excluded = blogPost.metadata.frontMatter.draft ||
|
|
98
|
+
blogPost.metadata.frontMatter.unlisted;
|
|
99
|
+
return !excluded;
|
|
100
|
+
}
|
|
101
|
+
async function createBlogFeedFiles({ blogPosts: allBlogPosts, options, siteConfig, outDir, locale, }) {
|
|
102
|
+
const blogPosts = allBlogPosts.filter(shouldBeInFeed);
|
|
97
103
|
const feed = await generateBlogFeed({
|
|
98
104
|
blogPosts,
|
|
99
105
|
options,
|
package/lib/frontMatter.js
CHANGED
|
@@ -23,7 +23,6 @@ const BlogFrontMatterSchema = utils_validation_1.JoiFrontMatter.object({
|
|
|
23
23
|
title: utils_validation_1.JoiFrontMatter.string().allow(''),
|
|
24
24
|
description: utils_validation_1.JoiFrontMatter.string().allow(''),
|
|
25
25
|
tags: utils_validation_1.FrontMatterTagsSchema,
|
|
26
|
-
draft: utils_validation_1.JoiFrontMatter.boolean(),
|
|
27
26
|
date: utils_validation_1.JoiFrontMatter.date().raw(),
|
|
28
27
|
// New multi-authors front matter:
|
|
29
28
|
authors: utils_validation_1.JoiFrontMatter.alternatives()
|
|
@@ -53,9 +52,11 @@ const BlogFrontMatterSchema = utils_validation_1.JoiFrontMatter.object({
|
|
|
53
52
|
keywords: utils_validation_1.JoiFrontMatter.array().items(utils_validation_1.JoiFrontMatter.string().required()),
|
|
54
53
|
hide_table_of_contents: utils_validation_1.JoiFrontMatter.boolean(),
|
|
55
54
|
...utils_validation_1.FrontMatterTOCHeadingLevels,
|
|
56
|
-
})
|
|
55
|
+
})
|
|
56
|
+
.messages({
|
|
57
57
|
'deprecate.error': '{#label} blog frontMatter field is deprecated. Please use {#alternative} instead.',
|
|
58
|
-
})
|
|
58
|
+
})
|
|
59
|
+
.concat(utils_validation_1.ContentVisibilitySchema);
|
|
59
60
|
function validateBlogPostFrontMatter(frontMatter) {
|
|
60
61
|
return (0, utils_validation_1.validateFrontMatter)(frontMatter, BlogFrontMatterSchema);
|
|
61
62
|
}
|
package/lib/index.js
CHANGED
|
@@ -15,6 +15,7 @@ const blogUtils_1 = require("./blogUtils");
|
|
|
15
15
|
const footnoteIDFixer_1 = tslib_1.__importDefault(require("./remark/footnoteIDFixer"));
|
|
16
16
|
const translations_1 = require("./translations");
|
|
17
17
|
const feed_1 = require("./feed");
|
|
18
|
+
const props_1 = require("./props");
|
|
18
19
|
async function pluginContentBlog(context, options) {
|
|
19
20
|
const { siteDir, siteConfig, generatedFilesDir, localizationDir, i18n: { currentLocale }, } = context;
|
|
20
21
|
const { onBrokenMarkdownLinks, baseUrl } = siteConfig;
|
|
@@ -50,6 +51,7 @@ async function pluginContentBlog(context, options) {
|
|
|
50
51
|
const baseBlogUrl = (0, utils_1.normalizeUrl)([baseUrl, routeBasePath]);
|
|
51
52
|
const blogTagsListPath = (0, utils_1.normalizeUrl)([baseBlogUrl, tagsBasePath]);
|
|
52
53
|
const blogPosts = await (0, blogUtils_1.generateBlogPosts)(contentPaths, context, options);
|
|
54
|
+
const listedBlogPosts = blogPosts.filter(blogUtils_1.shouldBeListed);
|
|
53
55
|
if (!blogPosts.length) {
|
|
54
56
|
return {
|
|
55
57
|
blogSidebarTitle,
|
|
@@ -61,15 +63,17 @@ async function pluginContentBlog(context, options) {
|
|
|
61
63
|
};
|
|
62
64
|
}
|
|
63
65
|
// Colocate next and prev metadata.
|
|
64
|
-
|
|
65
|
-
const prevItem = index > 0 ?
|
|
66
|
+
listedBlogPosts.forEach((blogPost, index) => {
|
|
67
|
+
const prevItem = index > 0 ? listedBlogPosts[index - 1] : null;
|
|
66
68
|
if (prevItem) {
|
|
67
69
|
blogPost.metadata.prevItem = {
|
|
68
70
|
title: prevItem.metadata.title,
|
|
69
71
|
permalink: prevItem.metadata.permalink,
|
|
70
72
|
};
|
|
71
73
|
}
|
|
72
|
-
const nextItem = index <
|
|
74
|
+
const nextItem = index < listedBlogPosts.length - 1
|
|
75
|
+
? listedBlogPosts[index + 1]
|
|
76
|
+
: null;
|
|
73
77
|
if (nextItem) {
|
|
74
78
|
blogPost.metadata.nextItem = {
|
|
75
79
|
title: nextItem.metadata.title,
|
|
@@ -78,7 +82,7 @@ async function pluginContentBlog(context, options) {
|
|
|
78
82
|
}
|
|
79
83
|
});
|
|
80
84
|
const blogListPaginated = (0, blogUtils_1.paginateBlogPosts)({
|
|
81
|
-
blogPosts,
|
|
85
|
+
blogPosts: listedBlogPosts,
|
|
82
86
|
blogTitle,
|
|
83
87
|
blogDescription,
|
|
84
88
|
postsPerPageOption,
|
|
@@ -146,6 +150,7 @@ async function pluginContentBlog(context, options) {
|
|
|
146
150
|
items: sidebarBlogPosts.map((blogPost) => ({
|
|
147
151
|
title: blogPost.metadata.title,
|
|
148
152
|
permalink: blogPost.metadata.permalink,
|
|
153
|
+
unlisted: blogPost.metadata.unlisted,
|
|
149
154
|
})),
|
|
150
155
|
}, null, 2));
|
|
151
156
|
// Create routes for blog entries.
|
|
@@ -187,12 +192,7 @@ async function pluginContentBlog(context, options) {
|
|
|
187
192
|
return;
|
|
188
193
|
}
|
|
189
194
|
async function createTagsListPage() {
|
|
190
|
-
const
|
|
191
|
-
label: tag.label,
|
|
192
|
-
permalink: tag.permalink,
|
|
193
|
-
count: tag.items.length,
|
|
194
|
-
}));
|
|
195
|
-
const tagsPropPath = await createData(`${(0, utils_1.docuHash)(`${blogTagsListPath}-tags`)}.json`, JSON.stringify(tagsProp, null, 2));
|
|
195
|
+
const tagsPropPath = await createData(`${(0, utils_1.docuHash)(`${blogTagsListPath}-tags`)}.json`, JSON.stringify((0, props_1.toTagsProp)({ blogTags }), null, 2));
|
|
196
196
|
addRoute({
|
|
197
197
|
path: blogTagsListPath,
|
|
198
198
|
component: blogTagsListComponent,
|
|
@@ -206,13 +206,7 @@ async function pluginContentBlog(context, options) {
|
|
|
206
206
|
async function createTagPostsListPage(tag) {
|
|
207
207
|
await Promise.all(tag.pages.map(async (blogPaginated) => {
|
|
208
208
|
const { metadata, items } = blogPaginated;
|
|
209
|
-
const
|
|
210
|
-
label: tag.label,
|
|
211
|
-
permalink: tag.permalink,
|
|
212
|
-
allTagsPath: blogTagsListPath,
|
|
213
|
-
count: tag.items.length,
|
|
214
|
-
};
|
|
215
|
-
const tagPropPath = await createData(`${(0, utils_1.docuHash)(metadata.permalink)}.json`, JSON.stringify(tagProp, null, 2));
|
|
209
|
+
const tagPropPath = await createData(`${(0, utils_1.docuHash)(metadata.permalink)}.json`, JSON.stringify((0, props_1.toTagProp)({ tag, blogTagsListPath }), null, 2));
|
|
216
210
|
const listMetadataPath = await createData(`${(0, utils_1.docuHash)(metadata.permalink)}-list.json`, JSON.stringify(metadata, null, 2));
|
|
217
211
|
addRoute({
|
|
218
212
|
path: metadata.permalink,
|
|
@@ -233,7 +227,7 @@ async function pluginContentBlog(context, options) {
|
|
|
233
227
|
translateContent({ content, translationFiles }) {
|
|
234
228
|
return (0, translations_1.translateContent)(content, translationFiles);
|
|
235
229
|
},
|
|
236
|
-
configureWebpack(_config, isServer,
|
|
230
|
+
configureWebpack(_config, isServer, utils, content) {
|
|
237
231
|
const { admonitions, rehypePlugins, remarkPlugins, truncateMarker, beforeDefaultRemarkPlugins, beforeDefaultRehypePlugins, } = options;
|
|
238
232
|
const markdownLoaderOptions = {
|
|
239
233
|
siteDir,
|
|
@@ -262,7 +256,6 @@ async function pluginContentBlog(context, options) {
|
|
|
262
256
|
// Trailing slash is important, see https://github.com/facebook/docusaurus/pull/3970
|
|
263
257
|
.map(utils_1.addTrailingPathSeparator),
|
|
264
258
|
use: [
|
|
265
|
-
getJSLoader({ isServer }),
|
|
266
259
|
{
|
|
267
260
|
loader: require.resolve('@docusaurus/mdx-loader'),
|
|
268
261
|
options: {
|
package/lib/options.js
CHANGED
|
@@ -14,7 +14,7 @@ exports.DEFAULT_OPTIONS = {
|
|
|
14
14
|
beforeDefaultRehypePlugins: [],
|
|
15
15
|
beforeDefaultRemarkPlugins: [],
|
|
16
16
|
admonitions: true,
|
|
17
|
-
truncateMarker: /<!--\s*truncate\s
|
|
17
|
+
truncateMarker: /<!--\s*truncate\s*-->|\{\/\*\s*truncate\s*\*\/\}/,
|
|
18
18
|
rehypePlugins: [],
|
|
19
19
|
remarkPlugins: [],
|
|
20
20
|
showReadingTime: true,
|
|
@@ -44,10 +44,7 @@ const PluginOptionSchema = utils_validation_1.Joi.object({
|
|
|
44
44
|
archiveBasePath: utils_validation_1.Joi.string()
|
|
45
45
|
.default(exports.DEFAULT_OPTIONS.archiveBasePath)
|
|
46
46
|
.allow(null),
|
|
47
|
-
routeBasePath: utils_validation_1.
|
|
48
|
-
// '' not allowed, see https://github.com/facebook/docusaurus/issues/3374
|
|
49
|
-
// .allow('')
|
|
50
|
-
.default(exports.DEFAULT_OPTIONS.routeBasePath),
|
|
47
|
+
routeBasePath: utils_validation_1.RouteBasePathSchema.default(exports.DEFAULT_OPTIONS.routeBasePath),
|
|
51
48
|
tagsBasePath: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.tagsBasePath),
|
|
52
49
|
include: utils_validation_1.Joi.array().items(utils_validation_1.Joi.string()).default(exports.DEFAULT_OPTIONS.include),
|
|
53
50
|
exclude: utils_validation_1.Joi.array().items(utils_validation_1.Joi.string()).default(exports.DEFAULT_OPTIONS.exclude),
|
package/lib/props.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
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 { TagsListItem, TagModule } from '@docusaurus/utils';
|
|
8
|
+
import type { BlogTag, BlogTags } from '@docusaurus/plugin-content-blog';
|
|
9
|
+
export declare function toTagsProp({ blogTags }: {
|
|
10
|
+
blogTags: BlogTags;
|
|
11
|
+
}): TagsListItem[];
|
|
12
|
+
export declare function toTagProp({ blogTagsListPath, tag, }: {
|
|
13
|
+
blogTagsListPath: string;
|
|
14
|
+
tag: BlogTag;
|
|
15
|
+
}): TagModule;
|
package/lib/props.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.toTagProp = exports.toTagsProp = void 0;
|
|
4
|
+
function toTagsProp({ blogTags }) {
|
|
5
|
+
return Object.values(blogTags)
|
|
6
|
+
.filter((tag) => !tag.unlisted)
|
|
7
|
+
.map((tag) => ({
|
|
8
|
+
label: tag.label,
|
|
9
|
+
permalink: tag.permalink,
|
|
10
|
+
count: tag.items.length,
|
|
11
|
+
}));
|
|
12
|
+
}
|
|
13
|
+
exports.toTagsProp = toTagsProp;
|
|
14
|
+
function toTagProp({ blogTagsListPath, tag, }) {
|
|
15
|
+
return {
|
|
16
|
+
label: tag.label,
|
|
17
|
+
permalink: tag.permalink,
|
|
18
|
+
allTagsPath: blogTagsListPath,
|
|
19
|
+
count: tag.items.length,
|
|
20
|
+
unlisted: tag.unlisted,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
exports.toTagProp = toTagProp;
|
package/lib/types.d.ts
CHANGED
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
import type { BrokenMarkdownLink, ContentPaths } from '@docusaurus/utils';
|
|
8
|
-
export
|
|
9
|
-
export
|
|
10
|
-
export
|
|
8
|
+
export type BlogContentPaths = ContentPaths;
|
|
9
|
+
export type BlogBrokenMarkdownLink = BrokenMarkdownLink<BlogContentPaths>;
|
|
10
|
+
export type BlogMarkdownLoaderOptions = {
|
|
11
11
|
siteDir: string;
|
|
12
12
|
contentPaths: BlogContentPaths;
|
|
13
13
|
truncateMarker: RegExp;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@docusaurus/plugin-content-blog",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0-alpha.0",
|
|
4
4
|
"description": "Blog plugin for Docusaurus.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "src/plugin-content-blog.d.ts",
|
|
@@ -18,29 +18,29 @@
|
|
|
18
18
|
},
|
|
19
19
|
"license": "MIT",
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@docusaurus/core": "
|
|
22
|
-
"@docusaurus/logger": "
|
|
23
|
-
"@docusaurus/mdx-loader": "
|
|
24
|
-
"@docusaurus/types": "
|
|
25
|
-
"@docusaurus/utils": "
|
|
26
|
-
"@docusaurus/utils-common": "
|
|
27
|
-
"@docusaurus/utils-validation": "
|
|
21
|
+
"@docusaurus/core": "3.0.0-alpha.0",
|
|
22
|
+
"@docusaurus/logger": "3.0.0-alpha.0",
|
|
23
|
+
"@docusaurus/mdx-loader": "3.0.0-alpha.0",
|
|
24
|
+
"@docusaurus/types": "3.0.0-alpha.0",
|
|
25
|
+
"@docusaurus/utils": "3.0.0-alpha.0",
|
|
26
|
+
"@docusaurus/utils-common": "3.0.0-alpha.0",
|
|
27
|
+
"@docusaurus/utils-validation": "3.0.0-alpha.0",
|
|
28
28
|
"cheerio": "^1.0.0-rc.12",
|
|
29
29
|
"feed": "^4.2.2",
|
|
30
|
-
"fs-extra": "^
|
|
30
|
+
"fs-extra": "^11.1.0",
|
|
31
31
|
"lodash": "^4.17.21",
|
|
32
32
|
"reading-time": "^1.5.0",
|
|
33
|
-
"tslib": "^2.
|
|
33
|
+
"tslib": "^2.5.0",
|
|
34
34
|
"unist-util-visit": "^2.0.3",
|
|
35
35
|
"utility-types": "^3.10.0",
|
|
36
|
-
"webpack": "^5.
|
|
36
|
+
"webpack": "^5.76.0"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
|
-
"react": "^
|
|
40
|
-
"react-dom": "^
|
|
39
|
+
"react": "^18.0.0",
|
|
40
|
+
"react-dom": "^18.0.0"
|
|
41
41
|
},
|
|
42
42
|
"engines": {
|
|
43
43
|
"node": ">=16.14"
|
|
44
44
|
},
|
|
45
|
-
"gitHead": "
|
|
45
|
+
"gitHead": "7327f7ff880ed97ad7855744e59c9c55d467a950"
|
|
46
46
|
}
|
package/src/blogUtils.ts
CHANGED
|
@@ -21,8 +21,11 @@ import {
|
|
|
21
21
|
Globby,
|
|
22
22
|
normalizeFrontMatterTags,
|
|
23
23
|
groupTaggedItems,
|
|
24
|
+
getTagVisibility,
|
|
24
25
|
getFileCommitDate,
|
|
25
26
|
getContentPathList,
|
|
27
|
+
isUnlisted,
|
|
28
|
+
isDraft,
|
|
26
29
|
} from '@docusaurus/utils';
|
|
27
30
|
import {validateBlogPostFrontMatter} from './frontMatter';
|
|
28
31
|
import {type AuthorsMap, getAuthorsMap, getBlogPostAuthors} from './authors';
|
|
@@ -96,6 +99,10 @@ export function paginateBlogPosts({
|
|
|
96
99
|
return pages;
|
|
97
100
|
}
|
|
98
101
|
|
|
102
|
+
export function shouldBeListed(blogPost: BlogPost): boolean {
|
|
103
|
+
return !blogPost.metadata.unlisted;
|
|
104
|
+
}
|
|
105
|
+
|
|
99
106
|
export function getBlogTags({
|
|
100
107
|
blogPosts,
|
|
101
108
|
...params
|
|
@@ -109,17 +116,23 @@ export function getBlogTags({
|
|
|
109
116
|
blogPosts,
|
|
110
117
|
(blogPost) => blogPost.metadata.tags,
|
|
111
118
|
);
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
119
|
+
return _.mapValues(groups, ({tag, items: tagBlogPosts}) => {
|
|
120
|
+
const tagVisibility = getTagVisibility({
|
|
121
|
+
items: tagBlogPosts,
|
|
122
|
+
isUnlisted: (item) => item.metadata.unlisted,
|
|
123
|
+
});
|
|
124
|
+
return {
|
|
125
|
+
label: tag.label,
|
|
126
|
+
items: tagVisibility.listedItems.map((item) => item.id),
|
|
127
|
+
permalink: tag.permalink,
|
|
128
|
+
pages: paginateBlogPosts({
|
|
129
|
+
blogPosts: tagVisibility.listedItems,
|
|
130
|
+
basePageUrl: tag.permalink,
|
|
131
|
+
...params,
|
|
132
|
+
}),
|
|
133
|
+
unlisted: tagVisibility.unlisted,
|
|
134
|
+
};
|
|
135
|
+
});
|
|
123
136
|
}
|
|
124
137
|
|
|
125
138
|
const DATE_FILENAME_REGEX =
|
|
@@ -219,7 +232,10 @@ async function processBlogSourceFile(
|
|
|
219
232
|
|
|
220
233
|
const aliasedSource = aliasedSitePath(blogSourceAbsolute, siteDir);
|
|
221
234
|
|
|
222
|
-
|
|
235
|
+
const draft = isDraft({frontMatter});
|
|
236
|
+
const unlisted = isUnlisted({frontMatter});
|
|
237
|
+
|
|
238
|
+
if (draft) {
|
|
223
239
|
return undefined;
|
|
224
240
|
}
|
|
225
241
|
|
|
@@ -326,6 +342,7 @@ async function processBlogSourceFile(
|
|
|
326
342
|
hasTruncateMarker: truncateMarker.test(content),
|
|
327
343
|
authors,
|
|
328
344
|
frontMatter,
|
|
345
|
+
unlisted,
|
|
329
346
|
},
|
|
330
347
|
content,
|
|
331
348
|
};
|
|
@@ -352,23 +369,25 @@ export async function generateBlogPosts(
|
|
|
352
369
|
authorsMapPath: options.authorsMapPath,
|
|
353
370
|
});
|
|
354
371
|
|
|
372
|
+
async function doProcessBlogSourceFile(blogSourceFile: string) {
|
|
373
|
+
try {
|
|
374
|
+
return await processBlogSourceFile(
|
|
375
|
+
blogSourceFile,
|
|
376
|
+
contentPaths,
|
|
377
|
+
context,
|
|
378
|
+
options,
|
|
379
|
+
authorsMap,
|
|
380
|
+
);
|
|
381
|
+
} catch (err) {
|
|
382
|
+
throw new Error(
|
|
383
|
+
`Processing of blog source file path=${blogSourceFile} failed.`,
|
|
384
|
+
{cause: err as Error},
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
355
389
|
const blogPosts = (
|
|
356
|
-
await Promise.all(
|
|
357
|
-
blogSourceFiles.map(async (blogSourceFile: string) => {
|
|
358
|
-
try {
|
|
359
|
-
return await processBlogSourceFile(
|
|
360
|
-
blogSourceFile,
|
|
361
|
-
contentPaths,
|
|
362
|
-
context,
|
|
363
|
-
options,
|
|
364
|
-
authorsMap,
|
|
365
|
-
);
|
|
366
|
-
} catch (err) {
|
|
367
|
-
logger.error`Processing of blog source file path=${blogSourceFile} failed.`;
|
|
368
|
-
throw err;
|
|
369
|
-
}
|
|
370
|
-
}),
|
|
371
|
-
)
|
|
390
|
+
await Promise.all(blogSourceFiles.map(doProcessBlogSourceFile))
|
|
372
391
|
).filter(Boolean) as BlogPost[];
|
|
373
392
|
|
|
374
393
|
blogPosts.sort(
|
package/src/feed.ts
CHANGED
|
@@ -158,8 +158,15 @@ async function createBlogFeedFile({
|
|
|
158
158
|
}
|
|
159
159
|
}
|
|
160
160
|
|
|
161
|
+
function shouldBeInFeed(blogPost: BlogPost): boolean {
|
|
162
|
+
const excluded =
|
|
163
|
+
blogPost.metadata.frontMatter.draft ||
|
|
164
|
+
blogPost.metadata.frontMatter.unlisted;
|
|
165
|
+
return !excluded;
|
|
166
|
+
}
|
|
167
|
+
|
|
161
168
|
export async function createBlogFeedFiles({
|
|
162
|
-
blogPosts,
|
|
169
|
+
blogPosts: allBlogPosts,
|
|
163
170
|
options,
|
|
164
171
|
siteConfig,
|
|
165
172
|
outDir,
|
|
@@ -171,6 +178,8 @@ export async function createBlogFeedFiles({
|
|
|
171
178
|
outDir: string;
|
|
172
179
|
locale: string;
|
|
173
180
|
}): Promise<void> {
|
|
181
|
+
const blogPosts = allBlogPosts.filter(shouldBeInFeed);
|
|
182
|
+
|
|
174
183
|
const feed = await generateBlogFeed({
|
|
175
184
|
blogPosts,
|
|
176
185
|
options,
|
package/src/frontMatter.ts
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
validateFrontMatter,
|
|
12
12
|
FrontMatterTagsSchema,
|
|
13
13
|
FrontMatterTOCHeadingLevels,
|
|
14
|
+
ContentVisibilitySchema,
|
|
14
15
|
} from '@docusaurus/utils-validation';
|
|
15
16
|
import type {BlogPostFrontMatter} from '@docusaurus/plugin-content-blog';
|
|
16
17
|
|
|
@@ -32,7 +33,6 @@ const BlogFrontMatterSchema = Joi.object<BlogPostFrontMatter>({
|
|
|
32
33
|
title: Joi.string().allow(''),
|
|
33
34
|
description: Joi.string().allow(''),
|
|
34
35
|
tags: FrontMatterTagsSchema,
|
|
35
|
-
draft: Joi.boolean(),
|
|
36
36
|
date: Joi.date().raw(),
|
|
37
37
|
|
|
38
38
|
// New multi-authors front matter:
|
|
@@ -69,10 +69,12 @@ const BlogFrontMatterSchema = Joi.object<BlogPostFrontMatter>({
|
|
|
69
69
|
hide_table_of_contents: Joi.boolean(),
|
|
70
70
|
|
|
71
71
|
...FrontMatterTOCHeadingLevels,
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
'
|
|
75
|
-
}
|
|
72
|
+
})
|
|
73
|
+
.messages({
|
|
74
|
+
'deprecate.error':
|
|
75
|
+
'{#label} blog frontMatter field is deprecated. Please use {#alternative} instead.',
|
|
76
|
+
})
|
|
77
|
+
.concat(ContentVisibilitySchema);
|
|
76
78
|
|
|
77
79
|
export function validateBlogPostFrontMatter(frontMatter: {
|
|
78
80
|
[key: string]: unknown;
|
package/src/index.ts
CHANGED
|
@@ -18,19 +18,19 @@ import {
|
|
|
18
18
|
getContentPathList,
|
|
19
19
|
getDataFilePath,
|
|
20
20
|
DEFAULT_PLUGIN_ID,
|
|
21
|
-
type TagsListItem,
|
|
22
|
-
type TagModule,
|
|
23
21
|
} from '@docusaurus/utils';
|
|
24
22
|
import {
|
|
25
23
|
generateBlogPosts,
|
|
26
24
|
getSourceToPermalink,
|
|
27
25
|
getBlogTags,
|
|
28
26
|
paginateBlogPosts,
|
|
27
|
+
shouldBeListed,
|
|
29
28
|
} from './blogUtils';
|
|
30
29
|
import footnoteIDFixer from './remark/footnoteIDFixer';
|
|
31
30
|
import {translateContent, getTranslationFiles} from './translations';
|
|
32
31
|
import {createBlogFeedFiles} from './feed';
|
|
33
32
|
|
|
33
|
+
import {toTagProp, toTagsProp} from './props';
|
|
34
34
|
import type {BlogContentPaths, BlogMarkdownLoaderOptions} from './types';
|
|
35
35
|
import type {LoadContext, Plugin, HtmlTags} from '@docusaurus/types';
|
|
36
36
|
import type {
|
|
@@ -112,6 +112,7 @@ export default async function pluginContentBlog(
|
|
|
112
112
|
const baseBlogUrl = normalizeUrl([baseUrl, routeBasePath]);
|
|
113
113
|
const blogTagsListPath = normalizeUrl([baseBlogUrl, tagsBasePath]);
|
|
114
114
|
const blogPosts = await generateBlogPosts(contentPaths, context, options);
|
|
115
|
+
const listedBlogPosts = blogPosts.filter(shouldBeListed);
|
|
115
116
|
|
|
116
117
|
if (!blogPosts.length) {
|
|
117
118
|
return {
|
|
@@ -125,8 +126,8 @@ export default async function pluginContentBlog(
|
|
|
125
126
|
}
|
|
126
127
|
|
|
127
128
|
// Colocate next and prev metadata.
|
|
128
|
-
|
|
129
|
-
const prevItem = index > 0 ?
|
|
129
|
+
listedBlogPosts.forEach((blogPost, index) => {
|
|
130
|
+
const prevItem = index > 0 ? listedBlogPosts[index - 1] : null;
|
|
130
131
|
if (prevItem) {
|
|
131
132
|
blogPost.metadata.prevItem = {
|
|
132
133
|
title: prevItem.metadata.title,
|
|
@@ -135,7 +136,9 @@ export default async function pluginContentBlog(
|
|
|
135
136
|
}
|
|
136
137
|
|
|
137
138
|
const nextItem =
|
|
138
|
-
index <
|
|
139
|
+
index < listedBlogPosts.length - 1
|
|
140
|
+
? listedBlogPosts[index + 1]
|
|
141
|
+
: null;
|
|
139
142
|
if (nextItem) {
|
|
140
143
|
blogPost.metadata.nextItem = {
|
|
141
144
|
title: nextItem.metadata.title,
|
|
@@ -145,7 +148,7 @@ export default async function pluginContentBlog(
|
|
|
145
148
|
});
|
|
146
149
|
|
|
147
150
|
const blogListPaginated: BlogPaginated[] = paginateBlogPosts({
|
|
148
|
-
blogPosts,
|
|
151
|
+
blogPosts: listedBlogPosts,
|
|
149
152
|
blogTitle,
|
|
150
153
|
blogDescription,
|
|
151
154
|
postsPerPageOption,
|
|
@@ -242,6 +245,7 @@ export default async function pluginContentBlog(
|
|
|
242
245
|
items: sidebarBlogPosts.map((blogPost) => ({
|
|
243
246
|
title: blogPost.metadata.title,
|
|
244
247
|
permalink: blogPost.metadata.permalink,
|
|
248
|
+
unlisted: blogPost.metadata.unlisted,
|
|
245
249
|
})),
|
|
246
250
|
},
|
|
247
251
|
null,
|
|
@@ -303,17 +307,10 @@ export default async function pluginContentBlog(
|
|
|
303
307
|
}
|
|
304
308
|
|
|
305
309
|
async function createTagsListPage() {
|
|
306
|
-
const tagsProp: TagsListItem[] = Object.values(blogTags).map((tag) => ({
|
|
307
|
-
label: tag.label,
|
|
308
|
-
permalink: tag.permalink,
|
|
309
|
-
count: tag.items.length,
|
|
310
|
-
}));
|
|
311
|
-
|
|
312
310
|
const tagsPropPath = await createData(
|
|
313
311
|
`${docuHash(`${blogTagsListPath}-tags`)}.json`,
|
|
314
|
-
JSON.stringify(
|
|
312
|
+
JSON.stringify(toTagsProp({blogTags}), null, 2),
|
|
315
313
|
);
|
|
316
|
-
|
|
317
314
|
addRoute({
|
|
318
315
|
path: blogTagsListPath,
|
|
319
316
|
component: blogTagsListComponent,
|
|
@@ -329,15 +326,9 @@ export default async function pluginContentBlog(
|
|
|
329
326
|
await Promise.all(
|
|
330
327
|
tag.pages.map(async (blogPaginated) => {
|
|
331
328
|
const {metadata, items} = blogPaginated;
|
|
332
|
-
const tagProp: TagModule = {
|
|
333
|
-
label: tag.label,
|
|
334
|
-
permalink: tag.permalink,
|
|
335
|
-
allTagsPath: blogTagsListPath,
|
|
336
|
-
count: tag.items.length,
|
|
337
|
-
};
|
|
338
329
|
const tagPropPath = await createData(
|
|
339
330
|
`${docuHash(metadata.permalink)}.json`,
|
|
340
|
-
JSON.stringify(
|
|
331
|
+
JSON.stringify(toTagProp({tag, blogTagsListPath}), null, 2),
|
|
341
332
|
);
|
|
342
333
|
|
|
343
334
|
const listMetadataPath = await createData(
|
|
@@ -368,7 +359,7 @@ export default async function pluginContentBlog(
|
|
|
368
359
|
return translateContent(content, translationFiles);
|
|
369
360
|
},
|
|
370
361
|
|
|
371
|
-
configureWebpack(_config, isServer,
|
|
362
|
+
configureWebpack(_config, isServer, utils, content) {
|
|
372
363
|
const {
|
|
373
364
|
admonitions,
|
|
374
365
|
rehypePlugins,
|
|
@@ -408,7 +399,6 @@ export default async function pluginContentBlog(
|
|
|
408
399
|
// Trailing slash is important, see https://github.com/facebook/docusaurus/pull/3970
|
|
409
400
|
.map(addTrailingPathSeparator),
|
|
410
401
|
use: [
|
|
411
|
-
getJSLoader({isServer}),
|
|
412
402
|
{
|
|
413
403
|
loader: require.resolve('@docusaurus/mdx-loader'),
|
|
414
404
|
options: {
|
package/src/options.ts
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
RemarkPluginsSchema,
|
|
11
11
|
RehypePluginsSchema,
|
|
12
12
|
AdmonitionsSchema,
|
|
13
|
+
RouteBasePathSchema,
|
|
13
14
|
URISchema,
|
|
14
15
|
} from '@docusaurus/utils-validation';
|
|
15
16
|
import {GlobExcludeDefault} from '@docusaurus/utils';
|
|
@@ -25,7 +26,7 @@ export const DEFAULT_OPTIONS: PluginOptions = {
|
|
|
25
26
|
beforeDefaultRehypePlugins: [],
|
|
26
27
|
beforeDefaultRemarkPlugins: [],
|
|
27
28
|
admonitions: true,
|
|
28
|
-
truncateMarker: /<!--\s*truncate\s
|
|
29
|
+
truncateMarker: /<!--\s*truncate\s*-->|\{\/\*\s*truncate\s*\*\/\}/,
|
|
29
30
|
rehypePlugins: [],
|
|
30
31
|
remarkPlugins: [],
|
|
31
32
|
showReadingTime: true,
|
|
@@ -56,10 +57,7 @@ const PluginOptionSchema = Joi.object<PluginOptions>({
|
|
|
56
57
|
archiveBasePath: Joi.string()
|
|
57
58
|
.default(DEFAULT_OPTIONS.archiveBasePath)
|
|
58
59
|
.allow(null),
|
|
59
|
-
routeBasePath:
|
|
60
|
-
// '' not allowed, see https://github.com/facebook/docusaurus/issues/3374
|
|
61
|
-
// .allow('')
|
|
62
|
-
.default(DEFAULT_OPTIONS.routeBasePath),
|
|
60
|
+
routeBasePath: RouteBasePathSchema.default(DEFAULT_OPTIONS.routeBasePath),
|
|
63
61
|
tagsBasePath: Joi.string().default(DEFAULT_OPTIONS.tagsBasePath),
|
|
64
62
|
include: Joi.array().items(Joi.string()).default(DEFAULT_OPTIONS.include),
|
|
65
63
|
exclude: Joi.array().items(Joi.string()).default(DEFAULT_OPTIONS.exclude),
|
|
@@ -97,6 +97,10 @@ yarn workspace v1.22.19image` is a collocated image path, this entry will be the
|
|
|
97
97
|
* Marks the post as draft and excludes it from the production build.
|
|
98
98
|
*/
|
|
99
99
|
draft?: boolean;
|
|
100
|
+
/**
|
|
101
|
+
* Marks the post as unlisted and visibly hides it unless directly accessed.
|
|
102
|
+
*/
|
|
103
|
+
unlisted?: boolean;
|
|
100
104
|
/**
|
|
101
105
|
* Will override the default publish date inferred from git/filename. Yaml
|
|
102
106
|
* only converts standard yyyy-MM-dd format to dates, so this may stay as a
|
|
@@ -229,6 +233,10 @@ yarn workspace v1.22.19image` is a collocated image path, this entry will be the
|
|
|
229
233
|
readonly frontMatter: BlogPostFrontMatter & {[key: string]: unknown};
|
|
230
234
|
/** Tags, normalized. */
|
|
231
235
|
readonly tags: Tag[];
|
|
236
|
+
/**
|
|
237
|
+
* Marks the post as unlisted and visibly hides it unless directly accessed.
|
|
238
|
+
*/
|
|
239
|
+
readonly unlisted: boolean;
|
|
232
240
|
};
|
|
233
241
|
/**
|
|
234
242
|
* @returns The edit URL that's directly plugged into metadata.
|
|
@@ -432,9 +440,15 @@ yarn workspace v1.22.19image` is a collocated image path, this entry will be the
|
|
|
432
440
|
}
|
|
433
441
|
>;
|
|
434
442
|
|
|
443
|
+
export type BlogSidebarItem = {
|
|
444
|
+
title: string;
|
|
445
|
+
permalink: string;
|
|
446
|
+
unlisted: boolean;
|
|
447
|
+
};
|
|
448
|
+
|
|
435
449
|
export type BlogSidebar = {
|
|
436
450
|
title: string;
|
|
437
|
-
items:
|
|
451
|
+
items: BlogSidebarItem[];
|
|
438
452
|
};
|
|
439
453
|
|
|
440
454
|
export type BlogContent = {
|
|
@@ -453,6 +467,7 @@ yarn workspace v1.22.19image` is a collocated image path, this entry will be the
|
|
|
453
467
|
/** Blog post permalinks. */
|
|
454
468
|
items: string[];
|
|
455
469
|
pages: BlogPaginated[];
|
|
470
|
+
unlisted: boolean;
|
|
456
471
|
};
|
|
457
472
|
|
|
458
473
|
export type BlogPost = {
|
package/src/props.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
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 {TagsListItem, TagModule} from '@docusaurus/utils';
|
|
8
|
+
import type {BlogTag, BlogTags} from '@docusaurus/plugin-content-blog';
|
|
9
|
+
|
|
10
|
+
export function toTagsProp({blogTags}: {blogTags: BlogTags}): TagsListItem[] {
|
|
11
|
+
return Object.values(blogTags)
|
|
12
|
+
.filter((tag) => !tag.unlisted)
|
|
13
|
+
.map((tag) => ({
|
|
14
|
+
label: tag.label,
|
|
15
|
+
permalink: tag.permalink,
|
|
16
|
+
count: tag.items.length,
|
|
17
|
+
}));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function toTagProp({
|
|
21
|
+
blogTagsListPath,
|
|
22
|
+
tag,
|
|
23
|
+
}: {
|
|
24
|
+
blogTagsListPath: string;
|
|
25
|
+
tag: BlogTag;
|
|
26
|
+
}): TagModule {
|
|
27
|
+
return {
|
|
28
|
+
label: tag.label,
|
|
29
|
+
permalink: tag.permalink,
|
|
30
|
+
allTagsPath: blogTagsListPath,
|
|
31
|
+
count: tag.items.length,
|
|
32
|
+
unlisted: tag.unlisted,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import visit from 'unist-util-visit';
|
|
9
9
|
import {simpleHash} from '@docusaurus/utils';
|
|
10
|
+
// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721
|
|
10
11
|
import type {Transformer} from 'unified';
|
|
11
12
|
import type {FootnoteReference, FootnoteDefinition} from 'mdast';
|
|
12
13
|
|