@docusaurus/plugin-content-blog 2.0.0-beta.15d451942 → 2.0.0-beta.18
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 +22 -0
- package/lib/authors.js +118 -0
- package/lib/blogUtils.d.ts +27 -7
- package/lib/blogUtils.js +213 -141
- package/lib/feed.d.ts +16 -0
- package/lib/feed.js +100 -0
- package/lib/frontMatter.d.ts +10 -0
- package/lib/frontMatter.js +62 -0
- package/lib/index.d.ts +5 -4
- package/lib/index.js +170 -182
- package/lib/markdownLoader.d.ts +3 -6
- package/lib/markdownLoader.js +6 -7
- package/lib/options.d.ts +10 -0
- package/lib/{pluginOptionSchema.js → options.js} +43 -13
- package/lib/translations.d.ts +11 -0
- package/lib/translations.js +53 -0
- package/lib/types.d.ts +11 -89
- package/package.json +21 -17
- package/src/authors.ts +164 -0
- package/src/blogUtils.ts +306 -192
- package/{types.d.ts → src/deps.d.ts} +1 -1
- package/src/feed.ts +175 -0
- package/src/frontMatter.ts +81 -0
- package/src/index.ts +226 -223
- package/src/markdownLoader.ts +11 -16
- package/src/{pluginOptionSchema.ts → options.ts} +54 -14
- package/src/plugin-content-blog.d.ts +591 -0
- package/src/translations.ts +66 -0
- package/src/types.ts +15 -105
- package/index.d.ts +0 -138
- package/lib/.tsbuildinfo +0 -4459
- package/lib/blogFrontMatter.d.ts +0 -28
- package/lib/blogFrontMatter.js +0 -50
- package/lib/pluginOptionSchema.d.ts +0 -33
- package/src/__tests__/__fixtures__/website/blog/2018-12-14-Happy-First-Birthday-Slash.md +0 -5
- package/src/__tests__/__fixtures__/website/blog/complex-slug.md +0 -7
- package/src/__tests__/__fixtures__/website/blog/date-matter.md +0 -5
- package/src/__tests__/__fixtures__/website/blog/draft.md +0 -6
- package/src/__tests__/__fixtures__/website/blog/heading-as-title.md +0 -5
- package/src/__tests__/__fixtures__/website/blog/simple-slug.md +0 -7
- package/src/__tests__/__fixtures__/website/blog-with-ref/2018-12-14-Happy-First-Birthday-Slash.md +0 -5
- package/src/__tests__/__fixtures__/website/blog-with-ref/post-with-broken-links.md +0 -11
- package/src/__tests__/__fixtures__/website/blog-with-ref/post.md +0 -5
- package/src/__tests__/__fixtures__/website/i18n/en/docusaurus-plugin-content-blog/2018-12-14-Happy-First-Birthday-Slash.md +0 -5
- package/src/__tests__/__fixtures__/website-blog-without-date/blog/no date.md +0 -1
- package/src/__tests__/__snapshots__/generateBlogFeed.test.ts.snap +0 -101
- package/src/__tests__/__snapshots__/linkify.test.ts.snap +0 -24
- package/src/__tests__/__snapshots__/pluginOptionSchema.test.ts.snap +0 -5
- package/src/__tests__/blogFrontMatter.test.ts +0 -265
- package/src/__tests__/generateBlogFeed.test.ts +0 -100
- package/src/__tests__/index.test.ts +0 -336
- package/src/__tests__/linkify.test.ts +0 -93
- package/src/__tests__/pluginOptionSchema.test.ts +0 -150
- package/src/blogFrontMatter.ts +0 -87
- package/tsconfig.json +0 -9
package/src/index.ts
CHANGED
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import fs from 'fs-extra';
|
|
9
8
|
import path from 'path';
|
|
10
9
|
import admonitions from 'remark-admonitions';
|
|
11
10
|
import {
|
|
@@ -16,46 +15,41 @@ import {
|
|
|
16
15
|
reportMessage,
|
|
17
16
|
posixPath,
|
|
18
17
|
addTrailingPathSeparator,
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
createAbsoluteFilePathMatcher,
|
|
19
|
+
getContentPathList,
|
|
20
|
+
getDataFilePath,
|
|
22
21
|
DEFAULT_PLUGIN_ID,
|
|
23
|
-
} from '@docusaurus/
|
|
24
|
-
import {
|
|
22
|
+
} from '@docusaurus/utils';
|
|
23
|
+
import {translateContent, getTranslationFiles} from './translations';
|
|
25
24
|
|
|
26
|
-
import {
|
|
27
|
-
|
|
25
|
+
import type {
|
|
26
|
+
BlogTag,
|
|
28
27
|
BlogTags,
|
|
29
28
|
BlogContent,
|
|
30
|
-
BlogItemsToMetadata,
|
|
31
|
-
TagsModule,
|
|
32
29
|
BlogPaginated,
|
|
33
|
-
BlogPost,
|
|
34
30
|
BlogContentPaths,
|
|
35
31
|
BlogMarkdownLoaderOptions,
|
|
36
32
|
} from './types';
|
|
37
|
-
import {
|
|
33
|
+
import type {LoadContext, Plugin, HtmlTags} from '@docusaurus/types';
|
|
38
34
|
import {
|
|
39
|
-
LoadContext,
|
|
40
|
-
ConfigureWebpackUtils,
|
|
41
|
-
Props,
|
|
42
|
-
Plugin,
|
|
43
|
-
HtmlTags,
|
|
44
|
-
OptionValidationContext,
|
|
45
|
-
ValidationResult,
|
|
46
|
-
} from '@docusaurus/types';
|
|
47
|
-
import {Configuration} from 'webpack';
|
|
48
|
-
import {
|
|
49
|
-
generateBlogFeed,
|
|
50
35
|
generateBlogPosts,
|
|
51
|
-
getContentPathList,
|
|
52
36
|
getSourceToPermalink,
|
|
37
|
+
getBlogTags,
|
|
38
|
+
paginateBlogPosts,
|
|
53
39
|
} from './blogUtils';
|
|
40
|
+
import {createBlogFeedFiles} from './feed';
|
|
41
|
+
import type {
|
|
42
|
+
PluginOptions,
|
|
43
|
+
BlogPostFrontMatter,
|
|
44
|
+
BlogPostMetadata,
|
|
45
|
+
Assets,
|
|
46
|
+
TagModule,
|
|
47
|
+
} from '@docusaurus/plugin-content-blog';
|
|
54
48
|
|
|
55
|
-
export default function pluginContentBlog(
|
|
49
|
+
export default async function pluginContentBlog(
|
|
56
50
|
context: LoadContext,
|
|
57
51
|
options: PluginOptions,
|
|
58
|
-
): Plugin<BlogContent
|
|
52
|
+
): Promise<Plugin<BlogContent>> {
|
|
59
53
|
if (options.admonitions) {
|
|
60
54
|
options.remarkPlugins = options.remarkPlugins.concat([
|
|
61
55
|
[admonitions, options.admonitions],
|
|
@@ -64,10 +58,11 @@ export default function pluginContentBlog(
|
|
|
64
58
|
|
|
65
59
|
const {
|
|
66
60
|
siteDir,
|
|
67
|
-
siteConfig
|
|
61
|
+
siteConfig,
|
|
68
62
|
generatedFilesDir,
|
|
69
63
|
i18n: {currentLocale},
|
|
70
64
|
} = context;
|
|
65
|
+
const {onBrokenMarkdownLinks, baseUrl} = siteConfig;
|
|
71
66
|
|
|
72
67
|
const contentPaths: BlogContentPaths = {
|
|
73
68
|
contentPath: path.resolve(siteDir, options.path),
|
|
@@ -88,37 +83,51 @@ export default function pluginContentBlog(
|
|
|
88
83
|
const aliasedSource = (source: string) =>
|
|
89
84
|
`~blog/${posixPath(path.relative(pluginDataDirRoot, source))}`;
|
|
90
85
|
|
|
91
|
-
|
|
86
|
+
const authorsMapFilePath = await getDataFilePath({
|
|
87
|
+
filePath: options.authorsMapPath,
|
|
88
|
+
contentPaths,
|
|
89
|
+
});
|
|
92
90
|
|
|
93
91
|
return {
|
|
94
92
|
name: 'docusaurus-plugin-content-blog',
|
|
95
93
|
|
|
96
94
|
getPathsToWatch() {
|
|
97
|
-
const {include
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
return include.map((pattern) => `${contentPath}/${pattern}`);
|
|
101
|
-
}),
|
|
95
|
+
const {include} = options;
|
|
96
|
+
const contentMarkdownGlobs = getContentPathList(contentPaths).flatMap(
|
|
97
|
+
(contentPath) => include.map((pattern) => `${contentPath}/${pattern}`),
|
|
102
98
|
);
|
|
103
|
-
},
|
|
104
|
-
|
|
105
|
-
getClientModules() {
|
|
106
|
-
const modules = [];
|
|
107
99
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
100
|
+
return [authorsMapFilePath, ...contentMarkdownGlobs].filter(
|
|
101
|
+
Boolean,
|
|
102
|
+
) as string[];
|
|
103
|
+
},
|
|
111
104
|
|
|
112
|
-
|
|
105
|
+
async getTranslationFiles() {
|
|
106
|
+
return getTranslationFiles(options);
|
|
113
107
|
},
|
|
114
108
|
|
|
115
109
|
// Fetches blog contents and returns metadata for the necessary routes.
|
|
116
110
|
async loadContent() {
|
|
117
|
-
const {
|
|
111
|
+
const {
|
|
112
|
+
postsPerPage: postsPerPageOption,
|
|
113
|
+
routeBasePath,
|
|
114
|
+
tagsBasePath,
|
|
115
|
+
blogDescription,
|
|
116
|
+
blogTitle,
|
|
117
|
+
blogSidebarTitle,
|
|
118
|
+
} = options;
|
|
119
|
+
|
|
120
|
+
const blogPosts = await generateBlogPosts(contentPaths, context, options);
|
|
118
121
|
|
|
119
|
-
blogPosts = await generateBlogPosts(contentPaths, context, options);
|
|
120
122
|
if (!blogPosts.length) {
|
|
121
|
-
return
|
|
123
|
+
return {
|
|
124
|
+
blogSidebarTitle,
|
|
125
|
+
blogPosts: [],
|
|
126
|
+
blogListPaginated: [],
|
|
127
|
+
blogTags: {},
|
|
128
|
+
blogTagsListPath: null,
|
|
129
|
+
blogTagsPaginated: [],
|
|
130
|
+
};
|
|
122
131
|
}
|
|
123
132
|
|
|
124
133
|
// Colocate next and prev metadata.
|
|
@@ -141,85 +150,30 @@ export default function pluginContentBlog(
|
|
|
141
150
|
}
|
|
142
151
|
});
|
|
143
152
|
|
|
144
|
-
|
|
145
|
-
// Example: `/blog`, `/blog/page/1`, `/blog/page/2`
|
|
146
|
-
const totalCount = blogPosts.length;
|
|
147
|
-
const numberOfPages = Math.ceil(totalCount / postsPerPage);
|
|
148
|
-
const {
|
|
149
|
-
siteConfig: {baseUrl = ''},
|
|
150
|
-
} = context;
|
|
151
|
-
const basePageUrl = normalizeUrl([baseUrl, routeBasePath]);
|
|
153
|
+
const baseBlogUrl = normalizeUrl([baseUrl, routeBasePath]);
|
|
152
154
|
|
|
153
|
-
const blogListPaginated: BlogPaginated[] =
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
for (let page = 0; page < numberOfPages; page += 1) {
|
|
162
|
-
blogListPaginated.push({
|
|
163
|
-
metadata: {
|
|
164
|
-
permalink: blogPaginationPermalink(page),
|
|
165
|
-
page: page + 1,
|
|
166
|
-
postsPerPage,
|
|
167
|
-
totalPages: numberOfPages,
|
|
168
|
-
totalCount,
|
|
169
|
-
previousPage: page !== 0 ? blogPaginationPermalink(page - 1) : null,
|
|
170
|
-
nextPage:
|
|
171
|
-
page < numberOfPages - 1
|
|
172
|
-
? blogPaginationPermalink(page + 1)
|
|
173
|
-
: null,
|
|
174
|
-
blogDescription: options.blogDescription,
|
|
175
|
-
blogTitle: options.blogTitle,
|
|
176
|
-
},
|
|
177
|
-
items: blogPosts
|
|
178
|
-
.slice(page * postsPerPage, (page + 1) * postsPerPage)
|
|
179
|
-
.map((item) => item.id),
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
const blogTags: BlogTags = {};
|
|
184
|
-
const tagsPath = normalizeUrl([basePageUrl, 'tags']);
|
|
185
|
-
blogPosts.forEach((blogPost) => {
|
|
186
|
-
const {tags} = blogPost.metadata;
|
|
187
|
-
if (!tags || tags.length === 0) {
|
|
188
|
-
// TODO: Extract tags out into a separate plugin.
|
|
189
|
-
// eslint-disable-next-line no-param-reassign
|
|
190
|
-
blogPost.metadata.tags = [];
|
|
191
|
-
return;
|
|
192
|
-
}
|
|
155
|
+
const blogListPaginated: BlogPaginated[] = paginateBlogPosts({
|
|
156
|
+
blogPosts,
|
|
157
|
+
blogTitle,
|
|
158
|
+
blogDescription,
|
|
159
|
+
postsPerPageOption,
|
|
160
|
+
basePageUrl: baseBlogUrl,
|
|
161
|
+
});
|
|
193
162
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
if (!blogTags[normalizedTag]) {
|
|
200
|
-
blogTags[normalizedTag] = {
|
|
201
|
-
// Will only use the name of the first occurrence of the tag.
|
|
202
|
-
name: tag.toLowerCase(),
|
|
203
|
-
items: [],
|
|
204
|
-
permalink,
|
|
205
|
-
};
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
blogTags[normalizedTag].items.push(blogPost.id);
|
|
209
|
-
|
|
210
|
-
return {
|
|
211
|
-
label: tag,
|
|
212
|
-
permalink,
|
|
213
|
-
};
|
|
214
|
-
}
|
|
215
|
-
return tag;
|
|
216
|
-
});
|
|
163
|
+
const blogTags: BlogTags = getBlogTags({
|
|
164
|
+
blogPosts,
|
|
165
|
+
postsPerPageOption,
|
|
166
|
+
blogDescription,
|
|
167
|
+
blogTitle,
|
|
217
168
|
});
|
|
218
169
|
|
|
170
|
+
const tagsPath = normalizeUrl([baseBlogUrl, tagsBasePath]);
|
|
171
|
+
|
|
219
172
|
const blogTagsListPath =
|
|
220
173
|
Object.keys(blogTags).length > 0 ? tagsPath : null;
|
|
221
174
|
|
|
222
175
|
return {
|
|
176
|
+
blogSidebarTitle,
|
|
223
177
|
blogPosts,
|
|
224
178
|
blogListPaginated,
|
|
225
179
|
blogTags,
|
|
@@ -237,22 +191,47 @@ export default function pluginContentBlog(
|
|
|
237
191
|
blogPostComponent,
|
|
238
192
|
blogTagsListComponent,
|
|
239
193
|
blogTagsPostsComponent,
|
|
194
|
+
blogArchiveComponent,
|
|
195
|
+
routeBasePath,
|
|
196
|
+
archiveBasePath,
|
|
240
197
|
} = options;
|
|
241
198
|
|
|
242
199
|
const {addRoute, createData} = actions;
|
|
243
200
|
const {
|
|
244
|
-
|
|
201
|
+
blogSidebarTitle,
|
|
202
|
+
blogPosts,
|
|
245
203
|
blogListPaginated,
|
|
246
204
|
blogTags,
|
|
247
205
|
blogTagsListPath,
|
|
248
206
|
} = blogContents;
|
|
249
207
|
|
|
250
|
-
const blogItemsToMetadata:
|
|
208
|
+
const blogItemsToMetadata: {[postId: string]: BlogPostMetadata} = {};
|
|
251
209
|
|
|
252
210
|
const sidebarBlogPosts =
|
|
253
211
|
options.blogSidebarCount === 'ALL'
|
|
254
212
|
? blogPosts
|
|
255
|
-
:
|
|
213
|
+
: blogPosts.slice(0, options.blogSidebarCount);
|
|
214
|
+
|
|
215
|
+
if (archiveBasePath && blogPosts.length) {
|
|
216
|
+
const archiveUrl = normalizeUrl([
|
|
217
|
+
baseUrl,
|
|
218
|
+
routeBasePath,
|
|
219
|
+
archiveBasePath,
|
|
220
|
+
]);
|
|
221
|
+
// creates a blog archive route
|
|
222
|
+
const archiveProp = await createData(
|
|
223
|
+
`${docuHash(archiveUrl)}.json`,
|
|
224
|
+
JSON.stringify({blogPosts}, null, 2),
|
|
225
|
+
);
|
|
226
|
+
addRoute({
|
|
227
|
+
path: archiveUrl,
|
|
228
|
+
component: blogArchiveComponent,
|
|
229
|
+
exact: true,
|
|
230
|
+
modules: {
|
|
231
|
+
archive: aliasedSource(archiveProp),
|
|
232
|
+
},
|
|
233
|
+
});
|
|
234
|
+
}
|
|
256
235
|
|
|
257
236
|
// This prop is useful to provide the blog list sidebar
|
|
258
237
|
const sidebarProp = await createData(
|
|
@@ -261,7 +240,7 @@ export default function pluginContentBlog(
|
|
|
261
240
|
`blog-post-list-prop-${pluginId}.json`,
|
|
262
241
|
JSON.stringify(
|
|
263
242
|
{
|
|
264
|
-
title:
|
|
243
|
+
title: blogSidebarTitle,
|
|
265
244
|
items: sidebarBlogPosts.map((blogPost) => ({
|
|
266
245
|
title: blogPost.metadata.title,
|
|
267
246
|
permalink: blogPost.metadata.permalink,
|
|
@@ -274,7 +253,7 @@ export default function pluginContentBlog(
|
|
|
274
253
|
|
|
275
254
|
// Create routes for blog entries.
|
|
276
255
|
await Promise.all(
|
|
277
|
-
|
|
256
|
+
blogPosts.map(async (blogPost) => {
|
|
278
257
|
const {id, metadata} = blogPost;
|
|
279
258
|
await createData(
|
|
280
259
|
// Note that this created data path must be in sync with
|
|
@@ -288,7 +267,7 @@ export default function pluginContentBlog(
|
|
|
288
267
|
component: blogPostComponent,
|
|
289
268
|
exact: true,
|
|
290
269
|
modules: {
|
|
291
|
-
sidebar: sidebarProp,
|
|
270
|
+
sidebar: aliasedSource(sidebarProp),
|
|
292
271
|
content: metadata.source,
|
|
293
272
|
},
|
|
294
273
|
});
|
|
@@ -312,19 +291,20 @@ export default function pluginContentBlog(
|
|
|
312
291
|
component: blogListComponent,
|
|
313
292
|
exact: true,
|
|
314
293
|
modules: {
|
|
315
|
-
sidebar: sidebarProp,
|
|
316
|
-
items: items.map((postID) =>
|
|
317
|
-
// To tell routes.js this is an import and not a nested object
|
|
318
|
-
|
|
294
|
+
sidebar: aliasedSource(sidebarProp),
|
|
295
|
+
items: items.map((postID) =>
|
|
296
|
+
// To tell routes.js this is an import and not a nested object
|
|
297
|
+
// to recurse.
|
|
298
|
+
({
|
|
319
299
|
content: {
|
|
320
300
|
__import: true,
|
|
321
|
-
path: blogItemsToMetadata[postID]
|
|
301
|
+
path: blogItemsToMetadata[postID]!.source,
|
|
322
302
|
query: {
|
|
323
303
|
truncated: true,
|
|
324
304
|
},
|
|
325
305
|
},
|
|
326
|
-
}
|
|
327
|
-
|
|
306
|
+
}),
|
|
307
|
+
),
|
|
328
308
|
metadata: aliasedSource(pageMetadataPath),
|
|
329
309
|
},
|
|
330
310
|
});
|
|
@@ -336,49 +316,60 @@ export default function pluginContentBlog(
|
|
|
336
316
|
return;
|
|
337
317
|
}
|
|
338
318
|
|
|
339
|
-
const tagsModule:
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
Object.keys(blogTags).map(async (tag) => {
|
|
343
|
-
const {name, items, permalink} = blogTags[tag];
|
|
344
|
-
|
|
345
|
-
tagsModule[tag] = {
|
|
319
|
+
const tagsModule: {[tagName: string]: TagModule} = Object.fromEntries(
|
|
320
|
+
Object.entries(blogTags).map(([, tag]) => {
|
|
321
|
+
const tagModule: TagModule = {
|
|
346
322
|
allTagsPath: blogTagsListPath,
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
permalink,
|
|
323
|
+
name: tag.name,
|
|
324
|
+
count: tag.items.length,
|
|
325
|
+
permalink: tag.permalink,
|
|
351
326
|
};
|
|
352
|
-
|
|
353
|
-
const tagsMetadataPath = await createData(
|
|
354
|
-
`${docuHash(permalink)}.json`,
|
|
355
|
-
JSON.stringify(tagsModule[tag], null, 2),
|
|
356
|
-
);
|
|
357
|
-
|
|
358
|
-
addRoute({
|
|
359
|
-
path: permalink,
|
|
360
|
-
component: blogTagsPostsComponent,
|
|
361
|
-
exact: true,
|
|
362
|
-
modules: {
|
|
363
|
-
sidebar: sidebarProp,
|
|
364
|
-
items: items.map((postID) => {
|
|
365
|
-
const metadata = blogItemsToMetadata[postID];
|
|
366
|
-
return {
|
|
367
|
-
content: {
|
|
368
|
-
__import: true,
|
|
369
|
-
path: metadata.source,
|
|
370
|
-
query: {
|
|
371
|
-
truncated: true,
|
|
372
|
-
},
|
|
373
|
-
},
|
|
374
|
-
};
|
|
375
|
-
}),
|
|
376
|
-
metadata: aliasedSource(tagsMetadataPath),
|
|
377
|
-
},
|
|
378
|
-
});
|
|
327
|
+
return [tag.name, tagModule];
|
|
379
328
|
}),
|
|
380
329
|
);
|
|
381
330
|
|
|
331
|
+
async function createTagRoutes(tag: BlogTag): Promise<void> {
|
|
332
|
+
await Promise.all(
|
|
333
|
+
tag.pages.map(async (blogPaginated) => {
|
|
334
|
+
const {metadata, items} = blogPaginated;
|
|
335
|
+
const tagsMetadataPath = await createData(
|
|
336
|
+
`${docuHash(metadata.permalink)}.json`,
|
|
337
|
+
JSON.stringify(tagsModule[tag.name], null, 2),
|
|
338
|
+
);
|
|
339
|
+
|
|
340
|
+
const listMetadataPath = await createData(
|
|
341
|
+
`${docuHash(metadata.permalink)}-list.json`,
|
|
342
|
+
JSON.stringify(metadata, null, 2),
|
|
343
|
+
);
|
|
344
|
+
|
|
345
|
+
addRoute({
|
|
346
|
+
path: metadata.permalink,
|
|
347
|
+
component: blogTagsPostsComponent,
|
|
348
|
+
exact: true,
|
|
349
|
+
modules: {
|
|
350
|
+
sidebar: aliasedSource(sidebarProp),
|
|
351
|
+
items: items.map((postID) => {
|
|
352
|
+
const blogPostMetadata = blogItemsToMetadata[postID]!;
|
|
353
|
+
return {
|
|
354
|
+
content: {
|
|
355
|
+
__import: true,
|
|
356
|
+
path: blogPostMetadata.source,
|
|
357
|
+
query: {
|
|
358
|
+
truncated: true,
|
|
359
|
+
},
|
|
360
|
+
},
|
|
361
|
+
};
|
|
362
|
+
}),
|
|
363
|
+
metadata: aliasedSource(tagsMetadataPath),
|
|
364
|
+
listMetadata: aliasedSource(listMetadataPath),
|
|
365
|
+
},
|
|
366
|
+
});
|
|
367
|
+
}),
|
|
368
|
+
);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
await Promise.all(Object.values(blogTags).map(createTagRoutes));
|
|
372
|
+
|
|
382
373
|
// Only create /tags page if there are tags.
|
|
383
374
|
if (Object.keys(blogTags).length > 0) {
|
|
384
375
|
const tagsListPath = await createData(
|
|
@@ -391,18 +382,18 @@ export default function pluginContentBlog(
|
|
|
391
382
|
component: blogTagsListComponent,
|
|
392
383
|
exact: true,
|
|
393
384
|
modules: {
|
|
394
|
-
sidebar: sidebarProp,
|
|
385
|
+
sidebar: aliasedSource(sidebarProp),
|
|
395
386
|
tags: aliasedSource(tagsListPath),
|
|
396
387
|
},
|
|
397
388
|
});
|
|
398
389
|
}
|
|
399
390
|
},
|
|
400
391
|
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
) {
|
|
392
|
+
translateContent({content, translationFiles}) {
|
|
393
|
+
return translateContent(content, translationFiles);
|
|
394
|
+
},
|
|
395
|
+
|
|
396
|
+
configureWebpack(_config, isServer, {getJSLoader}, content) {
|
|
406
397
|
const {
|
|
407
398
|
rehypePlugins,
|
|
408
399
|
remarkPlugins,
|
|
@@ -415,7 +406,7 @@ export default function pluginContentBlog(
|
|
|
415
406
|
siteDir,
|
|
416
407
|
contentPaths,
|
|
417
408
|
truncateMarker,
|
|
418
|
-
sourceToPermalink: getSourceToPermalink(blogPosts),
|
|
409
|
+
sourceToPermalink: getSourceToPermalink(content.blogPosts),
|
|
419
410
|
onBrokenMarkdownLink: (brokenMarkdownLink) => {
|
|
420
411
|
if (onBrokenMarkdownLinks === 'ignore') {
|
|
421
412
|
return;
|
|
@@ -427,6 +418,7 @@ export default function pluginContentBlog(
|
|
|
427
418
|
},
|
|
428
419
|
};
|
|
429
420
|
|
|
421
|
+
const contentDirs = getContentPathList(contentPaths);
|
|
430
422
|
return {
|
|
431
423
|
resolve: {
|
|
432
424
|
alias: {
|
|
@@ -436,8 +428,8 @@ export default function pluginContentBlog(
|
|
|
436
428
|
module: {
|
|
437
429
|
rules: [
|
|
438
430
|
{
|
|
439
|
-
test:
|
|
440
|
-
include:
|
|
431
|
+
test: /\.mdx?$/i,
|
|
432
|
+
include: contentDirs
|
|
441
433
|
// Trailing slash is important, see https://github.com/facebook/docusaurus/pull/3970
|
|
442
434
|
.map(addTrailingPathSeparator),
|
|
443
435
|
use: [
|
|
@@ -449,16 +441,41 @@ export default function pluginContentBlog(
|
|
|
449
441
|
rehypePlugins,
|
|
450
442
|
beforeDefaultRemarkPlugins,
|
|
451
443
|
beforeDefaultRehypePlugins,
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
444
|
+
staticDirs: siteConfig.staticDirectories.map((dir) =>
|
|
445
|
+
path.resolve(siteDir, dir),
|
|
446
|
+
),
|
|
447
|
+
siteDir,
|
|
448
|
+
isMDXPartial: createAbsoluteFilePathMatcher(
|
|
449
|
+
options.exclude,
|
|
450
|
+
contentDirs,
|
|
451
|
+
),
|
|
455
452
|
metadataPath: (mdxPath: string) => {
|
|
453
|
+
// Note that metadataPath must be the same/in-sync as
|
|
454
|
+
// the path from createData for each MDX.
|
|
456
455
|
const aliasedPath = aliasedSitePath(mdxPath, siteDir);
|
|
457
456
|
return path.join(
|
|
458
457
|
dataDir,
|
|
459
458
|
`${docuHash(aliasedPath)}.json`,
|
|
460
459
|
);
|
|
461
460
|
},
|
|
461
|
+
// For blog posts a title in markdown is always removed
|
|
462
|
+
// Blog posts title are rendered separately
|
|
463
|
+
removeContentTitle: true,
|
|
464
|
+
|
|
465
|
+
// Assets allow to convert some relative images paths to
|
|
466
|
+
// require() calls
|
|
467
|
+
createAssets: ({
|
|
468
|
+
frontMatter,
|
|
469
|
+
metadata,
|
|
470
|
+
}: {
|
|
471
|
+
frontMatter: BlogPostFrontMatter;
|
|
472
|
+
metadata: BlogPostMetadata;
|
|
473
|
+
}): Assets => ({
|
|
474
|
+
image: frontMatter.image,
|
|
475
|
+
authorsImageUrls: metadata.authors.map(
|
|
476
|
+
(author) => author.imageURL,
|
|
477
|
+
),
|
|
478
|
+
}),
|
|
462
479
|
},
|
|
463
480
|
},
|
|
464
481
|
{
|
|
@@ -472,67 +489,59 @@ export default function pluginContentBlog(
|
|
|
472
489
|
};
|
|
473
490
|
},
|
|
474
491
|
|
|
475
|
-
async postBuild({outDir}
|
|
476
|
-
if (!options.feedOptions
|
|
492
|
+
async postBuild({outDir, content}) {
|
|
493
|
+
if (!options.feedOptions.type) {
|
|
477
494
|
return;
|
|
478
495
|
}
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
if (!feed) {
|
|
496
|
+
const {blogPosts} = content;
|
|
497
|
+
if (!blogPosts.length) {
|
|
483
498
|
return;
|
|
484
499
|
}
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
options.routeBasePath,
|
|
493
|
-
`${feedType}.xml`,
|
|
494
|
-
);
|
|
495
|
-
const feedContent = feedType === 'rss' ? feed.rss2() : feed.atom1();
|
|
496
|
-
try {
|
|
497
|
-
await fs.outputFile(feedPath, feedContent);
|
|
498
|
-
} catch (err) {
|
|
499
|
-
throw new Error(`Generating ${feedType} feed failed: ${err}`);
|
|
500
|
-
}
|
|
501
|
-
}),
|
|
502
|
-
);
|
|
500
|
+
await createBlogFeedFiles({
|
|
501
|
+
blogPosts,
|
|
502
|
+
options,
|
|
503
|
+
outDir,
|
|
504
|
+
siteConfig,
|
|
505
|
+
locale: currentLocale,
|
|
506
|
+
});
|
|
503
507
|
},
|
|
504
508
|
|
|
505
|
-
injectHtmlTags() {
|
|
509
|
+
injectHtmlTags({content}) {
|
|
510
|
+
if (!content.blogPosts.length) {
|
|
511
|
+
return {};
|
|
512
|
+
}
|
|
513
|
+
|
|
506
514
|
if (!options.feedOptions?.type) {
|
|
507
515
|
return {};
|
|
508
516
|
}
|
|
517
|
+
|
|
509
518
|
const feedTypes = options.feedOptions.type;
|
|
510
|
-
const
|
|
511
|
-
siteConfig: {title},
|
|
512
|
-
baseUrl,
|
|
513
|
-
} = context;
|
|
519
|
+
const feedTitle = options.feedOptions.title ?? context.siteConfig.title;
|
|
514
520
|
const feedsConfig = {
|
|
515
521
|
rss: {
|
|
516
522
|
type: 'application/rss+xml',
|
|
517
523
|
path: 'rss.xml',
|
|
518
|
-
title: `${
|
|
524
|
+
title: `${feedTitle} RSS Feed`,
|
|
519
525
|
},
|
|
520
526
|
atom: {
|
|
521
527
|
type: 'application/atom+xml',
|
|
522
528
|
path: 'atom.xml',
|
|
523
|
-
title: `${
|
|
529
|
+
title: `${feedTitle} Atom Feed`,
|
|
530
|
+
},
|
|
531
|
+
json: {
|
|
532
|
+
type: 'application/json',
|
|
533
|
+
path: 'feed.json',
|
|
534
|
+
title: `${feedTitle} JSON Feed`,
|
|
524
535
|
},
|
|
525
536
|
};
|
|
526
537
|
const headTags: HtmlTags = [];
|
|
527
538
|
|
|
528
539
|
feedTypes.forEach((feedType) => {
|
|
529
|
-
const
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
const {type, path: feedConfigPath, title: feedConfigTitle} = feedConfig;
|
|
540
|
+
const {
|
|
541
|
+
type,
|
|
542
|
+
path: feedConfigPath,
|
|
543
|
+
title: feedConfigTitle,
|
|
544
|
+
} = feedsConfig[feedType];
|
|
536
545
|
|
|
537
546
|
headTags.push({
|
|
538
547
|
tagName: 'link',
|
|
@@ -556,10 +565,4 @@ export default function pluginContentBlog(
|
|
|
556
565
|
};
|
|
557
566
|
}
|
|
558
567
|
|
|
559
|
-
export
|
|
560
|
-
validate,
|
|
561
|
-
options,
|
|
562
|
-
}: OptionValidationContext<PluginOptions>): ValidationResult<PluginOptions> {
|
|
563
|
-
const validatedOptions = validate(PluginOptionSchema, options);
|
|
564
|
-
return validatedOptions;
|
|
565
|
-
}
|
|
568
|
+
export {validateOptions} from './options';
|