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