@docusaurus/plugin-content-blog 2.0.0-beta.8bda3b2db → 2.0.0-beta.9
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/.tsbuildinfo +1 -1
- package/lib/authors.d.ts +23 -0
- package/lib/authors.js +150 -0
- package/lib/blogFrontMatter.d.ts +19 -6
- package/lib/blogFrontMatter.js +31 -19
- package/lib/blogUtils.d.ts +10 -4
- package/lib/blogUtils.js +142 -136
- package/lib/feed.d.ts +20 -0
- package/lib/feed.js +90 -0
- package/lib/index.d.ts +1 -1
- package/lib/index.js +98 -98
- package/lib/markdownLoader.d.ts +3 -6
- package/lib/markdownLoader.js +5 -5
- package/lib/pluginOptionSchema.d.ts +3 -26
- package/lib/pluginOptionSchema.js +24 -7
- package/lib/translations.d.ts +10 -0
- package/lib/translations.js +53 -0
- package/lib/types.d.ts +53 -14
- package/package.json +15 -13
- package/src/__tests__/__fixtures__/authorsMapFiles/authors.json +29 -0
- package/src/__tests__/__fixtures__/authorsMapFiles/authors.yml +27 -0
- package/src/__tests__/__fixtures__/authorsMapFiles/authorsBad1.json +5 -0
- package/src/__tests__/__fixtures__/authorsMapFiles/authorsBad1.yml +3 -0
- package/src/__tests__/__fixtures__/authorsMapFiles/authorsBad2.json +3 -0
- package/src/__tests__/__fixtures__/authorsMapFiles/authorsBad2.yml +2 -0
- package/src/__tests__/__fixtures__/authorsMapFiles/authorsBad3.json +8 -0
- package/src/__tests__/__fixtures__/authorsMapFiles/authorsBad3.yml +3 -0
- package/src/__tests__/__fixtures__/component/Typography.tsx +6 -0
- package/src/__tests__/__fixtures__/getAuthorsMapFilePath/contentPathEmpty/empty +0 -0
- package/src/__tests__/__fixtures__/getAuthorsMapFilePath/contentPathJson1/authors.json +0 -0
- package/src/__tests__/__fixtures__/getAuthorsMapFilePath/contentPathJson2/authors.json +0 -0
- package/src/__tests__/__fixtures__/getAuthorsMapFilePath/contentPathNestedYml/sub/folder/authors.yml +0 -0
- package/src/__tests__/__fixtures__/getAuthorsMapFilePath/contentPathYml1/authors.yml +0 -0
- package/src/__tests__/__fixtures__/getAuthorsMapFilePath/contentPathYml2/authors.yml +0 -0
- package/src/__tests__/__fixtures__/website/blog/2018-12-14-Happy-First-Birthday-Slash.md +3 -0
- package/src/__tests__/__fixtures__/website/blog/_partials/somePartial.md +3 -0
- package/src/__tests__/__fixtures__/website/blog/_partials/subfolder/somePartial.md +3 -0
- package/src/__tests__/__fixtures__/website/blog/_somePartial.md +3 -0
- package/src/__tests__/__fixtures__/website/blog/authors.yml +4 -0
- package/src/__tests__/__fixtures__/website/blog/mdx-blog-post.mdx +36 -0
- package/src/__tests__/__fixtures__/website/blog/mdx-require-blog-post.mdx +14 -0
- package/src/__tests__/__fixtures__/website/blog/simple-slug.md +4 -0
- package/src/__tests__/__fixtures__/website/i18n/en/docusaurus-plugin-content-blog/2018-12-14-Happy-First-Birthday-Slash.md +3 -0
- package/src/__tests__/__fixtures__/website/i18n/en/docusaurus-plugin-content-blog/authors.yml +5 -0
- package/src/__tests__/__fixtures__/website/static/img/docusaurus.png +0 -0
- package/src/__tests__/__snapshots__/feed.test.ts.snap +164 -0
- package/src/__tests__/__snapshots__/translations.test.ts.snap +64 -0
- package/src/__tests__/authors.test.ts +608 -0
- package/src/__tests__/blogFrontMatter.test.ts +93 -16
- package/src/__tests__/blogUtils.test.ts +94 -0
- package/src/__tests__/{generateBlogFeed.test.ts → feed.test.ts} +35 -9
- package/src/__tests__/index.test.ts +73 -12
- package/src/__tests__/pluginOptionSchema.test.ts +3 -3
- package/src/__tests__/translations.test.ts +92 -0
- package/src/authors.ts +202 -0
- package/src/blogFrontMatter.ts +73 -33
- package/src/blogUtils.ts +202 -179
- package/src/feed.ts +129 -0
- package/src/index.ts +124 -103
- package/src/markdownLoader.ts +8 -12
- package/{index.d.ts → src/plugin-content-blog.d.ts} +35 -31
- package/src/pluginOptionSchema.ts +27 -9
- package/src/translations.ts +63 -0
- package/src/types.ts +68 -16
- package/src/__tests__/__snapshots__/generateBlogFeed.test.ts.snap +0 -76
package/lib/index.js
CHANGED
|
@@ -8,14 +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
|
|
12
|
-
const
|
|
13
|
-
const remark_admonitions_1 = tslib_1.__importDefault(require("remark-admonitions"));
|
|
11
|
+
const path_1 = (0, tslib_1.__importDefault)(require("path"));
|
|
12
|
+
const remark_admonitions_1 = (0, tslib_1.__importDefault)(require("remark-admonitions"));
|
|
14
13
|
const utils_1 = require("@docusaurus/utils");
|
|
15
14
|
const constants_1 = require("@docusaurus/core/lib/constants");
|
|
16
|
-
const
|
|
15
|
+
const translations_1 = require("./translations");
|
|
17
16
|
const pluginOptionSchema_1 = require("./pluginOptionSchema");
|
|
18
17
|
const blogUtils_1 = require("./blogUtils");
|
|
18
|
+
const feed_1 = require("./feed");
|
|
19
19
|
function pluginContentBlog(context, options) {
|
|
20
20
|
var _a;
|
|
21
21
|
if (options.admonitions) {
|
|
@@ -23,10 +23,11 @@ function pluginContentBlog(context, options) {
|
|
|
23
23
|
[remark_admonitions_1.default, options.admonitions],
|
|
24
24
|
]);
|
|
25
25
|
}
|
|
26
|
-
const { siteDir, siteConfig
|
|
26
|
+
const { siteDir, siteConfig, generatedFilesDir, i18n: { currentLocale }, } = context;
|
|
27
|
+
const { onBrokenMarkdownLinks, baseUrl } = siteConfig;
|
|
27
28
|
const contentPaths = {
|
|
28
29
|
contentPath: path_1.default.resolve(siteDir, options.path),
|
|
29
|
-
contentPathLocalized: utils_1.getPluginI18nPath({
|
|
30
|
+
contentPathLocalized: (0, utils_1.getPluginI18nPath)({
|
|
30
31
|
siteDir,
|
|
31
32
|
locale: currentLocale,
|
|
32
33
|
pluginName: 'docusaurus-plugin-content-blog',
|
|
@@ -36,29 +37,33 @@ function pluginContentBlog(context, options) {
|
|
|
36
37
|
const pluginId = (_a = options.id) !== null && _a !== void 0 ? _a : constants_1.DEFAULT_PLUGIN_ID;
|
|
37
38
|
const pluginDataDirRoot = path_1.default.join(generatedFilesDir, 'docusaurus-plugin-content-blog');
|
|
38
39
|
const dataDir = path_1.default.join(pluginDataDirRoot, pluginId);
|
|
39
|
-
const aliasedSource = (source) => `~blog/${utils_1.posixPath(path_1.default.relative(pluginDataDirRoot, source))}`;
|
|
40
|
-
let blogPosts = [];
|
|
40
|
+
const aliasedSource = (source) => `~blog/${(0, utils_1.posixPath)(path_1.default.relative(pluginDataDirRoot, source))}`;
|
|
41
41
|
return {
|
|
42
42
|
name: 'docusaurus-plugin-content-blog',
|
|
43
43
|
getPathsToWatch() {
|
|
44
|
-
const { include
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
})
|
|
44
|
+
const { include, authorsMapPath } = options;
|
|
45
|
+
const contentMarkdownGlobs = (0, blogUtils_1.getContentPathList)(contentPaths).flatMap((contentPath) => include.map((pattern) => `${contentPath}/${pattern}`));
|
|
46
|
+
// TODO: we should read this path in plugin! but plugins do not support async init for now :'(
|
|
47
|
+
// const authorsMapFilePath = await getAuthorsMapFilePath({authorsMapPath,contentPaths,});
|
|
48
|
+
// simplified impl, better than nothing for now:
|
|
49
|
+
const authorsMapFilePath = path_1.default.join(contentPaths.contentPath, authorsMapPath);
|
|
50
|
+
return [authorsMapFilePath, ...contentMarkdownGlobs];
|
|
48
51
|
},
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
if (options.admonitions) {
|
|
52
|
-
modules.push(require.resolve('remark-admonitions/styles/infima.css'));
|
|
53
|
-
}
|
|
54
|
-
return modules;
|
|
52
|
+
async getTranslationFiles() {
|
|
53
|
+
return (0, translations_1.getTranslationFiles)(options);
|
|
55
54
|
},
|
|
56
55
|
// Fetches blog contents and returns metadata for the necessary routes.
|
|
57
56
|
async loadContent() {
|
|
58
|
-
const { postsPerPage, routeBasePath } = options;
|
|
59
|
-
blogPosts = await blogUtils_1.generateBlogPosts(contentPaths, context, options);
|
|
57
|
+
const { postsPerPage: postsPerPageOption, routeBasePath, tagsBasePath, blogDescription, blogTitle, blogSidebarTitle, } = options;
|
|
58
|
+
const blogPosts = await (0, blogUtils_1.generateBlogPosts)(contentPaths, context, options);
|
|
60
59
|
if (!blogPosts.length) {
|
|
61
|
-
return
|
|
60
|
+
return {
|
|
61
|
+
blogSidebarTitle,
|
|
62
|
+
blogPosts: [],
|
|
63
|
+
blogListPaginated: [],
|
|
64
|
+
blogTags: {},
|
|
65
|
+
blogTagsListPath: null,
|
|
66
|
+
};
|
|
62
67
|
}
|
|
63
68
|
// Colocate next and prev metadata.
|
|
64
69
|
blogPosts.forEach((blogPost, index) => {
|
|
@@ -80,14 +85,14 @@ function pluginContentBlog(context, options) {
|
|
|
80
85
|
// Blog pagination routes.
|
|
81
86
|
// Example: `/blog`, `/blog/page/1`, `/blog/page/2`
|
|
82
87
|
const totalCount = blogPosts.length;
|
|
88
|
+
const postsPerPage = postsPerPageOption === 'ALL' ? totalCount : postsPerPageOption;
|
|
83
89
|
const numberOfPages = Math.ceil(totalCount / postsPerPage);
|
|
84
|
-
const
|
|
85
|
-
const basePageUrl = utils_1.normalizeUrl([baseUrl, routeBasePath]);
|
|
90
|
+
const baseBlogUrl = (0, utils_1.normalizeUrl)([baseUrl, routeBasePath]);
|
|
86
91
|
const blogListPaginated = [];
|
|
87
92
|
function blogPaginationPermalink(page) {
|
|
88
93
|
return page > 0
|
|
89
|
-
? utils_1.normalizeUrl([
|
|
90
|
-
:
|
|
94
|
+
? (0, utils_1.normalizeUrl)([baseBlogUrl, `page/${page + 1}`])
|
|
95
|
+
: baseBlogUrl;
|
|
91
96
|
}
|
|
92
97
|
for (let page = 0; page < numberOfPages; page += 1) {
|
|
93
98
|
blogListPaginated.push({
|
|
@@ -101,48 +106,19 @@ function pluginContentBlog(context, options) {
|
|
|
101
106
|
nextPage: page < numberOfPages - 1
|
|
102
107
|
? blogPaginationPermalink(page + 1)
|
|
103
108
|
: null,
|
|
104
|
-
blogDescription
|
|
105
|
-
blogTitle
|
|
109
|
+
blogDescription,
|
|
110
|
+
blogTitle,
|
|
106
111
|
},
|
|
107
112
|
items: blogPosts
|
|
108
113
|
.slice(page * postsPerPage, (page + 1) * postsPerPage)
|
|
109
114
|
.map((item) => item.id),
|
|
110
115
|
});
|
|
111
116
|
}
|
|
112
|
-
const blogTags =
|
|
113
|
-
const tagsPath = utils_1.normalizeUrl([
|
|
114
|
-
blogPosts.forEach((blogPost) => {
|
|
115
|
-
const { tags } = blogPost.metadata;
|
|
116
|
-
if (!tags || tags.length === 0) {
|
|
117
|
-
// TODO: Extract tags out into a separate plugin.
|
|
118
|
-
// eslint-disable-next-line no-param-reassign
|
|
119
|
-
blogPost.metadata.tags = [];
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
// eslint-disable-next-line no-param-reassign
|
|
123
|
-
blogPost.metadata.tags = tags.map((tag) => {
|
|
124
|
-
if (typeof tag === 'string') {
|
|
125
|
-
const normalizedTag = lodash_1.kebabCase(tag);
|
|
126
|
-
const permalink = utils_1.normalizeUrl([tagsPath, normalizedTag]);
|
|
127
|
-
if (!blogTags[normalizedTag]) {
|
|
128
|
-
blogTags[normalizedTag] = {
|
|
129
|
-
// Will only use the name of the first occurrence of the tag.
|
|
130
|
-
name: tag.toLowerCase(),
|
|
131
|
-
items: [],
|
|
132
|
-
permalink,
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
blogTags[normalizedTag].items.push(blogPost.id);
|
|
136
|
-
return {
|
|
137
|
-
label: tag,
|
|
138
|
-
permalink,
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
return tag;
|
|
142
|
-
});
|
|
143
|
-
});
|
|
117
|
+
const blogTags = (0, blogUtils_1.getBlogTags)(blogPosts);
|
|
118
|
+
const tagsPath = (0, utils_1.normalizeUrl)([baseBlogUrl, tagsBasePath]);
|
|
144
119
|
const blogTagsListPath = Object.keys(blogTags).length > 0 ? tagsPath : null;
|
|
145
120
|
return {
|
|
121
|
+
blogSidebarTitle,
|
|
146
122
|
blogPosts,
|
|
147
123
|
blogListPaginated,
|
|
148
124
|
blogTags,
|
|
@@ -153,31 +129,46 @@ function pluginContentBlog(context, options) {
|
|
|
153
129
|
if (!blogContents) {
|
|
154
130
|
return;
|
|
155
131
|
}
|
|
156
|
-
const { blogListComponent, blogPostComponent, blogTagsListComponent, blogTagsPostsComponent, } = options;
|
|
132
|
+
const { blogListComponent, blogPostComponent, blogTagsListComponent, blogTagsPostsComponent, routeBasePath, archiveBasePath, } = options;
|
|
157
133
|
const { addRoute, createData } = actions;
|
|
158
|
-
const { blogPosts
|
|
134
|
+
const { blogSidebarTitle, blogPosts, blogListPaginated, blogTags, blogTagsListPath, } = blogContents;
|
|
159
135
|
const blogItemsToMetadata = {};
|
|
160
136
|
const sidebarBlogPosts = options.blogSidebarCount === 'ALL'
|
|
161
137
|
? blogPosts
|
|
162
|
-
:
|
|
138
|
+
: blogPosts.slice(0, options.blogSidebarCount);
|
|
139
|
+
const archiveUrl = (0, utils_1.normalizeUrl)([
|
|
140
|
+
baseUrl,
|
|
141
|
+
routeBasePath,
|
|
142
|
+
archiveBasePath,
|
|
143
|
+
]);
|
|
144
|
+
// creates a blog archive route
|
|
145
|
+
const archiveProp = await createData(`${(0, utils_1.docuHash)(archiveUrl)}.json`, JSON.stringify({ blogPosts }, null, 2));
|
|
146
|
+
addRoute({
|
|
147
|
+
path: archiveUrl,
|
|
148
|
+
component: '@theme/BlogArchivePage',
|
|
149
|
+
exact: true,
|
|
150
|
+
modules: {
|
|
151
|
+
archive: aliasedSource(archiveProp),
|
|
152
|
+
},
|
|
153
|
+
});
|
|
163
154
|
// This prop is useful to provide the blog list sidebar
|
|
164
155
|
const sidebarProp = await createData(
|
|
165
156
|
// Note that this created data path must be in sync with
|
|
166
157
|
// metadataPath provided to mdx-loader.
|
|
167
158
|
`blog-post-list-prop-${pluginId}.json`, JSON.stringify({
|
|
168
|
-
title:
|
|
159
|
+
title: blogSidebarTitle,
|
|
169
160
|
items: sidebarBlogPosts.map((blogPost) => ({
|
|
170
161
|
title: blogPost.metadata.title,
|
|
171
162
|
permalink: blogPost.metadata.permalink,
|
|
172
163
|
})),
|
|
173
164
|
}, null, 2));
|
|
174
165
|
// Create routes for blog entries.
|
|
175
|
-
await Promise.all(
|
|
166
|
+
await Promise.all(blogPosts.map(async (blogPost) => {
|
|
176
167
|
const { id, metadata } = blogPost;
|
|
177
168
|
await createData(
|
|
178
169
|
// Note that this created data path must be in sync with
|
|
179
170
|
// metadataPath provided to mdx-loader.
|
|
180
|
-
`${utils_1.docuHash(metadata.source)}.json`, JSON.stringify(metadata, null, 2));
|
|
171
|
+
`${(0, utils_1.docuHash)(metadata.source)}.json`, JSON.stringify(metadata, null, 2));
|
|
181
172
|
addRoute({
|
|
182
173
|
path: metadata.permalink,
|
|
183
174
|
component: blogPostComponent,
|
|
@@ -193,7 +184,7 @@ function pluginContentBlog(context, options) {
|
|
|
193
184
|
await Promise.all(blogListPaginated.map(async (listPage) => {
|
|
194
185
|
const { metadata, items } = listPage;
|
|
195
186
|
const { permalink } = metadata;
|
|
196
|
-
const pageMetadataPath = await createData(`${utils_1.docuHash(permalink)}.json`, JSON.stringify(metadata, null, 2));
|
|
187
|
+
const pageMetadataPath = await createData(`${(0, utils_1.docuHash)(permalink)}.json`, JSON.stringify(metadata, null, 2));
|
|
197
188
|
addRoute({
|
|
198
189
|
path: permalink,
|
|
199
190
|
component: blogListComponent,
|
|
@@ -223,6 +214,7 @@ function pluginContentBlog(context, options) {
|
|
|
223
214
|
const tagsModule = {};
|
|
224
215
|
await Promise.all(Object.keys(blogTags).map(async (tag) => {
|
|
225
216
|
const { name, items, permalink } = blogTags[tag];
|
|
217
|
+
// Refactor all this, see docs implementation
|
|
226
218
|
tagsModule[tag] = {
|
|
227
219
|
allTagsPath: blogTagsListPath,
|
|
228
220
|
slug: tag,
|
|
@@ -230,7 +222,7 @@ function pluginContentBlog(context, options) {
|
|
|
230
222
|
count: items.length,
|
|
231
223
|
permalink,
|
|
232
224
|
};
|
|
233
|
-
const tagsMetadataPath = await createData(`${utils_1.docuHash(permalink)}.json`, JSON.stringify(tagsModule[tag], null, 2));
|
|
225
|
+
const tagsMetadataPath = await createData(`${(0, utils_1.docuHash)(permalink)}.json`, JSON.stringify(tagsModule[tag], null, 2));
|
|
234
226
|
addRoute({
|
|
235
227
|
path: permalink,
|
|
236
228
|
component: blogTagsPostsComponent,
|
|
@@ -255,7 +247,7 @@ function pluginContentBlog(context, options) {
|
|
|
255
247
|
}));
|
|
256
248
|
// Only create /tags page if there are tags.
|
|
257
249
|
if (Object.keys(blogTags).length > 0) {
|
|
258
|
-
const tagsListPath = await createData(`${utils_1.docuHash(`${blogTagsListPath}-tags`)}.json`, JSON.stringify(tagsModule, null, 2));
|
|
250
|
+
const tagsListPath = await createData(`${(0, utils_1.docuHash)(`${blogTagsListPath}-tags`)}.json`, JSON.stringify(tagsModule, null, 2));
|
|
259
251
|
addRoute({
|
|
260
252
|
path: blogTagsListPath,
|
|
261
253
|
component: blogTagsListComponent,
|
|
@@ -267,20 +259,24 @@ function pluginContentBlog(context, options) {
|
|
|
267
259
|
});
|
|
268
260
|
}
|
|
269
261
|
},
|
|
270
|
-
|
|
262
|
+
translateContent({ content, translationFiles }) {
|
|
263
|
+
return (0, translations_1.translateContent)(content, translationFiles);
|
|
264
|
+
},
|
|
265
|
+
configureWebpack(_config, isServer, { getJSLoader }, content) {
|
|
271
266
|
const { rehypePlugins, remarkPlugins, truncateMarker, beforeDefaultRemarkPlugins, beforeDefaultRehypePlugins, } = options;
|
|
272
267
|
const markdownLoaderOptions = {
|
|
273
268
|
siteDir,
|
|
274
269
|
contentPaths,
|
|
275
270
|
truncateMarker,
|
|
276
|
-
sourceToPermalink: blogUtils_1.getSourceToPermalink(blogPosts),
|
|
271
|
+
sourceToPermalink: (0, blogUtils_1.getSourceToPermalink)(content.blogPosts),
|
|
277
272
|
onBrokenMarkdownLink: (brokenMarkdownLink) => {
|
|
278
273
|
if (onBrokenMarkdownLinks === 'ignore') {
|
|
279
274
|
return;
|
|
280
275
|
}
|
|
281
|
-
utils_1.reportMessage(`Blog markdown link couldn't be resolved: (${brokenMarkdownLink.link}) in ${brokenMarkdownLink.filePath}`, onBrokenMarkdownLinks);
|
|
276
|
+
(0, utils_1.reportMessage)(`Blog markdown link couldn't be resolved: (${brokenMarkdownLink.link}) in ${brokenMarkdownLink.filePath}`, onBrokenMarkdownLinks);
|
|
282
277
|
},
|
|
283
278
|
};
|
|
279
|
+
const contentDirs = (0, blogUtils_1.getContentPathList)(contentPaths);
|
|
284
280
|
return {
|
|
285
281
|
resolve: {
|
|
286
282
|
alias: {
|
|
@@ -291,7 +287,7 @@ function pluginContentBlog(context, options) {
|
|
|
291
287
|
rules: [
|
|
292
288
|
{
|
|
293
289
|
test: /(\.mdx?)$/,
|
|
294
|
-
include:
|
|
290
|
+
include: contentDirs
|
|
295
291
|
// Trailing slash is important, see https://github.com/facebook/docusaurus/pull/3970
|
|
296
292
|
.map(utils_1.addTrailingPathSeparator),
|
|
297
293
|
use: [
|
|
@@ -304,15 +300,23 @@ function pluginContentBlog(context, options) {
|
|
|
304
300
|
beforeDefaultRemarkPlugins,
|
|
305
301
|
beforeDefaultRehypePlugins,
|
|
306
302
|
staticDir: path_1.default.join(siteDir, constants_1.STATIC_DIR_NAME),
|
|
307
|
-
|
|
308
|
-
// the path from createData for each MDX.
|
|
303
|
+
isMDXPartial: (0, utils_1.createAbsoluteFilePathMatcher)(options.exclude, contentDirs),
|
|
309
304
|
metadataPath: (mdxPath) => {
|
|
310
|
-
|
|
311
|
-
|
|
305
|
+
// Note that metadataPath must be the same/in-sync as
|
|
306
|
+
// the path from createData for each MDX.
|
|
307
|
+
const aliasedPath = (0, utils_1.aliasedSitePath)(mdxPath, siteDir);
|
|
308
|
+
return path_1.default.join(dataDir, `${(0, utils_1.docuHash)(aliasedPath)}.json`);
|
|
312
309
|
},
|
|
313
310
|
// For blog posts a title in markdown is always removed
|
|
314
311
|
// Blog posts title are rendered separately
|
|
315
312
|
removeContentTitle: true,
|
|
313
|
+
// Assets allow to convert some relative images paths to require() calls
|
|
314
|
+
createAssets: ({ frontMatter, metadata, }) => {
|
|
315
|
+
return {
|
|
316
|
+
image: frontMatter.image,
|
|
317
|
+
authorsImageUrls: metadata.authors.map((author) => author.imageURL),
|
|
318
|
+
};
|
|
319
|
+
},
|
|
316
320
|
},
|
|
317
321
|
},
|
|
318
322
|
{
|
|
@@ -326,46 +330,42 @@ function pluginContentBlog(context, options) {
|
|
|
326
330
|
};
|
|
327
331
|
},
|
|
328
332
|
async postBuild({ outDir }) {
|
|
329
|
-
|
|
330
|
-
if (!((_a = options.feedOptions) === null || _a === void 0 ? void 0 : _a.type)) {
|
|
333
|
+
if (!options.feedOptions.type) {
|
|
331
334
|
return;
|
|
332
335
|
}
|
|
333
|
-
|
|
334
|
-
|
|
336
|
+
// TODO: we shouldn't need to re-read the posts here!
|
|
337
|
+
// postBuild should receive loadedContent
|
|
338
|
+
const blogPosts = await (0, blogUtils_1.generateBlogPosts)(contentPaths, context, options);
|
|
339
|
+
if (!blogPosts.length) {
|
|
335
340
|
return;
|
|
336
341
|
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
}
|
|
344
|
-
catch (err) {
|
|
345
|
-
throw new Error(`Generating ${feedType} feed failed: ${err}.`);
|
|
346
|
-
}
|
|
347
|
-
}));
|
|
342
|
+
await (0, feed_1.createBlogFeedFiles)({
|
|
343
|
+
blogPosts,
|
|
344
|
+
options,
|
|
345
|
+
outDir,
|
|
346
|
+
siteConfig,
|
|
347
|
+
});
|
|
348
348
|
},
|
|
349
|
-
injectHtmlTags() {
|
|
350
|
-
var _a;
|
|
351
|
-
if (!blogPosts.length) {
|
|
349
|
+
injectHtmlTags({ content }) {
|
|
350
|
+
var _a, _b;
|
|
351
|
+
if (!content.blogPosts.length) {
|
|
352
352
|
return {};
|
|
353
353
|
}
|
|
354
354
|
if (!((_a = options.feedOptions) === null || _a === void 0 ? void 0 : _a.type)) {
|
|
355
355
|
return {};
|
|
356
356
|
}
|
|
357
357
|
const feedTypes = options.feedOptions.type;
|
|
358
|
-
const
|
|
358
|
+
const feedTitle = (_b = options.feedOptions.title) !== null && _b !== void 0 ? _b : context.siteConfig.title;
|
|
359
359
|
const feedsConfig = {
|
|
360
360
|
rss: {
|
|
361
361
|
type: 'application/rss+xml',
|
|
362
362
|
path: 'rss.xml',
|
|
363
|
-
title: `${
|
|
363
|
+
title: `${feedTitle} RSS Feed`,
|
|
364
364
|
},
|
|
365
365
|
atom: {
|
|
366
366
|
type: 'application/atom+xml',
|
|
367
367
|
path: 'atom.xml',
|
|
368
|
-
title: `${
|
|
368
|
+
title: `${feedTitle} Atom Feed`,
|
|
369
369
|
},
|
|
370
370
|
};
|
|
371
371
|
const headTags = [];
|
|
@@ -380,7 +380,7 @@ function pluginContentBlog(context, options) {
|
|
|
380
380
|
attributes: {
|
|
381
381
|
rel: 'alternate',
|
|
382
382
|
type,
|
|
383
|
-
href: utils_1.normalizeUrl([
|
|
383
|
+
href: (0, utils_1.normalizeUrl)([
|
|
384
384
|
baseUrl,
|
|
385
385
|
options.routeBasePath,
|
|
386
386
|
feedConfigPath,
|
package/lib/markdownLoader.d.ts
CHANGED
|
@@ -4,9 +4,6 @@
|
|
|
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
|
-
|
|
9
|
-
|
|
10
|
-
}
|
|
11
|
-
declare const markdownLoader: Loader;
|
|
12
|
-
export default markdownLoader;
|
|
7
|
+
import { BlogMarkdownLoaderOptions } from './types';
|
|
8
|
+
import type { LoaderContext } from 'webpack';
|
|
9
|
+
export default function markdownLoader(this: LoaderContext<BlogMarkdownLoaderOptions>, source: string): void;
|
package/lib/markdownLoader.js
CHANGED
|
@@ -8,24 +8,24 @@
|
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
9
|
const blogUtils_1 = require("./blogUtils");
|
|
10
10
|
const loader_utils_1 = require("loader-utils");
|
|
11
|
-
|
|
11
|
+
function markdownLoader(source) {
|
|
12
12
|
const filePath = this.resourcePath;
|
|
13
13
|
const fileString = source;
|
|
14
14
|
const callback = this.async();
|
|
15
15
|
const markdownLoaderOptions = this.getOptions();
|
|
16
16
|
// Linkify blog posts
|
|
17
|
-
let finalContent = blogUtils_1.linkify({
|
|
17
|
+
let finalContent = (0, blogUtils_1.linkify)({
|
|
18
18
|
fileString,
|
|
19
19
|
filePath,
|
|
20
20
|
...markdownLoaderOptions,
|
|
21
21
|
});
|
|
22
22
|
// Truncate content if requested (e.g: file.md?truncated=true).
|
|
23
23
|
const truncated = this.resourceQuery
|
|
24
|
-
? !!loader_utils_1.parseQuery(this.resourceQuery).truncated
|
|
24
|
+
? !!(0, loader_utils_1.parseQuery)(this.resourceQuery).truncated
|
|
25
25
|
: undefined;
|
|
26
26
|
if (truncated) {
|
|
27
|
-
finalContent = blogUtils_1.truncate(finalContent, markdownLoaderOptions.truncateMarker);
|
|
27
|
+
finalContent = (0, blogUtils_1.truncate)(finalContent, markdownLoaderOptions.truncateMarker);
|
|
28
28
|
}
|
|
29
29
|
return callback && callback(null, finalContent);
|
|
30
|
-
}
|
|
30
|
+
}
|
|
31
31
|
exports.default = markdownLoader;
|
|
@@ -5,29 +5,6 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
import { Joi } from '@docusaurus/utils-validation';
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
};
|
|
12
|
-
beforeDefaultRehypePlugins: never[];
|
|
13
|
-
beforeDefaultRemarkPlugins: never[];
|
|
14
|
-
admonitions: {};
|
|
15
|
-
truncateMarker: RegExp;
|
|
16
|
-
rehypePlugins: never[];
|
|
17
|
-
remarkPlugins: never[];
|
|
18
|
-
showReadingTime: boolean;
|
|
19
|
-
blogTagsPostsComponent: string;
|
|
20
|
-
blogTagsListComponent: string;
|
|
21
|
-
blogPostComponent: string;
|
|
22
|
-
blogListComponent: string;
|
|
23
|
-
blogDescription: string;
|
|
24
|
-
blogTitle: string;
|
|
25
|
-
blogSidebarCount: number;
|
|
26
|
-
blogSidebarTitle: string;
|
|
27
|
-
postsPerPage: number;
|
|
28
|
-
include: string[];
|
|
29
|
-
routeBasePath: string;
|
|
30
|
-
path: string;
|
|
31
|
-
editLocalizedFiles: boolean;
|
|
32
|
-
};
|
|
33
|
-
export declare const PluginOptionSchema: Joi.ObjectSchema<any>;
|
|
8
|
+
import { PluginOptions } from './types';
|
|
9
|
+
export declare const DEFAULT_OPTIONS: PluginOptions;
|
|
10
|
+
export declare const PluginOptionSchema: Joi.ObjectSchema<PluginOptions>;
|
|
@@ -8,8 +8,9 @@
|
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
9
|
exports.PluginOptionSchema = exports.DEFAULT_OPTIONS = void 0;
|
|
10
10
|
const utils_validation_1 = require("@docusaurus/utils-validation");
|
|
11
|
+
const utils_1 = require("@docusaurus/utils");
|
|
11
12
|
exports.DEFAULT_OPTIONS = {
|
|
12
|
-
feedOptions: { type: ['rss', 'atom'] },
|
|
13
|
+
feedOptions: { type: ['rss', 'atom'], copyright: '' },
|
|
13
14
|
beforeDefaultRehypePlugins: [],
|
|
14
15
|
beforeDefaultRemarkPlugins: [],
|
|
15
16
|
admonitions: {},
|
|
@@ -26,21 +27,28 @@ exports.DEFAULT_OPTIONS = {
|
|
|
26
27
|
blogSidebarCount: 5,
|
|
27
28
|
blogSidebarTitle: 'Recent posts',
|
|
28
29
|
postsPerPage: 10,
|
|
29
|
-
include: ['
|
|
30
|
+
include: ['**/*.{md,mdx}'],
|
|
31
|
+
exclude: utils_1.GlobExcludeDefault,
|
|
30
32
|
routeBasePath: 'blog',
|
|
33
|
+
tagsBasePath: 'tags',
|
|
34
|
+
archiveBasePath: 'archive',
|
|
31
35
|
path: 'blog',
|
|
32
36
|
editLocalizedFiles: false,
|
|
37
|
+
authorsMapPath: 'authors.yml',
|
|
38
|
+
readingTime: ({ content, defaultReadingTime }) => defaultReadingTime({ content }),
|
|
33
39
|
};
|
|
34
40
|
exports.PluginOptionSchema = utils_validation_1.Joi.object({
|
|
35
41
|
path: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.path),
|
|
42
|
+
archiveBasePath: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.archiveBasePath),
|
|
36
43
|
routeBasePath: utils_validation_1.Joi.string()
|
|
37
44
|
// '' not allowed, see https://github.com/facebook/docusaurus/issues/3374
|
|
38
45
|
// .allow('')
|
|
39
46
|
.default(exports.DEFAULT_OPTIONS.routeBasePath),
|
|
47
|
+
tagsBasePath: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.tagsBasePath),
|
|
40
48
|
include: utils_validation_1.Joi.array().items(utils_validation_1.Joi.string()).default(exports.DEFAULT_OPTIONS.include),
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
.min(1)
|
|
49
|
+
exclude: utils_validation_1.Joi.array().items(utils_validation_1.Joi.string()).default(exports.DEFAULT_OPTIONS.exclude),
|
|
50
|
+
postsPerPage: utils_validation_1.Joi.alternatives()
|
|
51
|
+
.try(utils_validation_1.Joi.equal('ALL').required(), utils_validation_1.Joi.number().integer().min(1).required())
|
|
44
52
|
.default(exports.DEFAULT_OPTIONS.postsPerPage),
|
|
45
53
|
blogListComponent: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.blogListComponent),
|
|
46
54
|
blogPostComponent: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.blogPostComponent),
|
|
@@ -51,7 +59,7 @@ exports.PluginOptionSchema = utils_validation_1.Joi.object({
|
|
|
51
59
|
.allow('')
|
|
52
60
|
.default(exports.DEFAULT_OPTIONS.blogDescription),
|
|
53
61
|
blogSidebarCount: utils_validation_1.Joi.alternatives()
|
|
54
|
-
.try(utils_validation_1.Joi.equal('ALL').required(), utils_validation_1.Joi.number().required())
|
|
62
|
+
.try(utils_validation_1.Joi.equal('ALL').required(), utils_validation_1.Joi.number().integer().min(0).required())
|
|
55
63
|
.default(exports.DEFAULT_OPTIONS.blogSidebarCount),
|
|
56
64
|
blogSidebarTitle: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.blogSidebarTitle),
|
|
57
65
|
showReadingTime: utils_validation_1.Joi.bool().default(exports.DEFAULT_OPTIONS.showReadingTime),
|
|
@@ -72,7 +80,16 @@ exports.PluginOptionSchema = utils_validation_1.Joi.object({
|
|
|
72
80
|
.default(exports.DEFAULT_OPTIONS.feedOptions.type),
|
|
73
81
|
title: utils_validation_1.Joi.string().allow(''),
|
|
74
82
|
description: utils_validation_1.Joi.string().allow(''),
|
|
75
|
-
|
|
83
|
+
// only add default value when user actually wants a feed (type is not null)
|
|
84
|
+
copyright: utils_validation_1.Joi.when('type', {
|
|
85
|
+
is: utils_validation_1.Joi.any().valid(null),
|
|
86
|
+
then: utils_validation_1.Joi.string().optional(),
|
|
87
|
+
otherwise: utils_validation_1.Joi.string()
|
|
88
|
+
.allow('')
|
|
89
|
+
.default(exports.DEFAULT_OPTIONS.feedOptions.copyright),
|
|
90
|
+
}),
|
|
76
91
|
language: utils_validation_1.Joi.string(),
|
|
77
92
|
}).default(exports.DEFAULT_OPTIONS.feedOptions),
|
|
93
|
+
authorsMapPath: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.authorsMapPath),
|
|
94
|
+
readingTime: utils_validation_1.Joi.function().default(() => exports.DEFAULT_OPTIONS.readingTime),
|
|
78
95
|
});
|
|
@@ -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 { BlogContent, PluginOptions } from './types';
|
|
8
|
+
import type { TranslationFiles } from '@docusaurus/types';
|
|
9
|
+
export declare function getTranslationFiles(options: PluginOptions): TranslationFiles;
|
|
10
|
+
export declare function translateContent(content: BlogContent, translationFiles: TranslationFiles): BlogContent;
|
|
@@ -0,0 +1,53 @@
|
|
|
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.translateContent = exports.getTranslationFiles = void 0;
|
|
10
|
+
function translateListPage(blogListPaginated, translations) {
|
|
11
|
+
return blogListPaginated.map((page) => {
|
|
12
|
+
const { items, metadata } = page;
|
|
13
|
+
return {
|
|
14
|
+
items,
|
|
15
|
+
metadata: {
|
|
16
|
+
...metadata,
|
|
17
|
+
blogTitle: translations.title.message,
|
|
18
|
+
blogDescription: translations.description.message,
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
function getTranslationFiles(options) {
|
|
24
|
+
return [
|
|
25
|
+
{
|
|
26
|
+
path: 'options',
|
|
27
|
+
content: {
|
|
28
|
+
title: {
|
|
29
|
+
message: options.blogTitle,
|
|
30
|
+
description: 'The title for the blog used in SEO',
|
|
31
|
+
},
|
|
32
|
+
description: {
|
|
33
|
+
message: options.blogDescription,
|
|
34
|
+
description: 'The description for the blog used in SEO',
|
|
35
|
+
},
|
|
36
|
+
'sidebar.title': {
|
|
37
|
+
message: options.blogSidebarTitle,
|
|
38
|
+
description: 'The label for the left sidebar',
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
];
|
|
43
|
+
}
|
|
44
|
+
exports.getTranslationFiles = getTranslationFiles;
|
|
45
|
+
function translateContent(content, translationFiles) {
|
|
46
|
+
const [{ content: optonsTranslations }] = translationFiles;
|
|
47
|
+
return {
|
|
48
|
+
...content,
|
|
49
|
+
blogSidebarTitle: optonsTranslations['sidebar.title'].message,
|
|
50
|
+
blogListPaginated: translateListPage(content.blogListPaginated, optonsTranslations),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
exports.translateContent = translateContent;
|