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