@docusaurus/plugin-content-blog 2.0.0-beta.fc64c12e4 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/authors.d.ts +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 +163 -194
- 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} +41 -14
- 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 -110
- package/package.json +23 -19
- package/src/authors.ts +168 -0
- package/src/blogUtils.ts +305 -205
- package/src/feed.ts +171 -0
- package/src/frontMatter.ts +81 -0
- package/src/index.ts +223 -258
- package/src/markdownLoader.ts +11 -16
- package/src/{pluginOptionSchema.ts → options.ts} +54 -16
- package/src/plugin-content-blog.d.ts +587 -0
- package/src/remark/footnoteIDFixer.ts +29 -0
- package/src/translations.ts +69 -0
- package/src/types.ts +2 -129
- package/index.d.ts +0 -138
- package/lib/.tsbuildinfo +0 -1
- package/lib/blogFrontMatter.d.ts +0 -28
- package/lib/pluginOptionSchema.d.ts +0 -34
- package/src/__tests__/__fixtures__/website/blog/2018-12-14-Happy-First-Birthday-Slash.md +0 -5
- package/src/__tests__/__fixtures__/website/blog/_partials/somePartial.md +0 -3
- package/src/__tests__/__fixtures__/website/blog/_partials/subfolder/somePartial.md +0 -3
- package/src/__tests__/__fixtures__/website/blog/_somePartial.md +0 -3
- 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 -116
- 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 -102
- 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/types.d.ts +0 -13
package/src/blogUtils.ts
CHANGED
|
@@ -6,20 +6,12 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import fs from 'fs-extra';
|
|
9
|
-
import chalk from 'chalk';
|
|
10
9
|
import path from 'path';
|
|
10
|
+
import _ from 'lodash';
|
|
11
|
+
import logger from '@docusaurus/logger';
|
|
11
12
|
import readingTime from 'reading-time';
|
|
12
|
-
import {Feed} from 'feed';
|
|
13
|
-
import {keyBy, mapValues} from 'lodash';
|
|
14
13
|
import {
|
|
15
|
-
|
|
16
|
-
BlogPost,
|
|
17
|
-
DateLink,
|
|
18
|
-
BlogContentPaths,
|
|
19
|
-
BlogMarkdownLoaderOptions,
|
|
20
|
-
} from './types';
|
|
21
|
-
import {
|
|
22
|
-
parseMarkdownFile,
|
|
14
|
+
parseMarkdownString,
|
|
23
15
|
normalizeUrl,
|
|
24
16
|
aliasedSitePath,
|
|
25
17
|
getEditUrl,
|
|
@@ -27,252 +19,365 @@ import {
|
|
|
27
19
|
posixPath,
|
|
28
20
|
replaceMarkdownLinks,
|
|
29
21
|
Globby,
|
|
22
|
+
normalizeFrontMatterTags,
|
|
23
|
+
groupTaggedItems,
|
|
24
|
+
getFileCommitDate,
|
|
25
|
+
getContentPathList,
|
|
30
26
|
} from '@docusaurus/utils';
|
|
31
|
-
import {
|
|
32
|
-
import {
|
|
27
|
+
import {validateBlogPostFrontMatter} from './frontMatter';
|
|
28
|
+
import {type AuthorsMap, getAuthorsMap, getBlogPostAuthors} from './authors';
|
|
29
|
+
import type {LoadContext} from '@docusaurus/types';
|
|
30
|
+
import type {
|
|
31
|
+
PluginOptions,
|
|
32
|
+
ReadingTimeFunction,
|
|
33
|
+
BlogPost,
|
|
34
|
+
BlogTags,
|
|
35
|
+
BlogPaginated,
|
|
36
|
+
} from '@docusaurus/plugin-content-blog';
|
|
37
|
+
import type {BlogContentPaths, BlogMarkdownLoaderOptions} from './types';
|
|
33
38
|
|
|
34
39
|
export function truncate(fileString: string, truncateMarker: RegExp): string {
|
|
35
40
|
return fileString.split(truncateMarker, 1).shift()!;
|
|
36
41
|
}
|
|
37
42
|
|
|
38
|
-
export function getSourceToPermalink(
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
return
|
|
42
|
-
|
|
43
|
-
(v) => v.metadata.permalink,
|
|
43
|
+
export function getSourceToPermalink(blogPosts: BlogPost[]): {
|
|
44
|
+
[aliasedPath: string]: string;
|
|
45
|
+
} {
|
|
46
|
+
return Object.fromEntries(
|
|
47
|
+
blogPosts.map(({metadata: {source, permalink}}) => [source, permalink]),
|
|
44
48
|
);
|
|
45
49
|
}
|
|
46
50
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
51
|
+
export function paginateBlogPosts({
|
|
52
|
+
blogPosts,
|
|
53
|
+
basePageUrl,
|
|
54
|
+
blogTitle,
|
|
55
|
+
blogDescription,
|
|
56
|
+
postsPerPageOption,
|
|
57
|
+
}: {
|
|
58
|
+
blogPosts: BlogPost[];
|
|
59
|
+
basePageUrl: string;
|
|
60
|
+
blogTitle: string;
|
|
61
|
+
blogDescription: string;
|
|
62
|
+
postsPerPageOption: number | 'ALL';
|
|
63
|
+
}): BlogPaginated[] {
|
|
64
|
+
const totalCount = blogPosts.length;
|
|
65
|
+
const postsPerPage =
|
|
66
|
+
postsPerPageOption === 'ALL' ? totalCount : postsPerPageOption;
|
|
67
|
+
const numberOfPages = Math.ceil(totalCount / postsPerPage);
|
|
68
|
+
|
|
69
|
+
const pages: BlogPaginated[] = [];
|
|
70
|
+
|
|
71
|
+
function permalink(page: number) {
|
|
72
|
+
return page > 0
|
|
73
|
+
? normalizeUrl([basePageUrl, `page/${page + 1}`])
|
|
74
|
+
: basePageUrl;
|
|
75
|
+
}
|
|
50
76
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
77
|
+
for (let page = 0; page < numberOfPages; page += 1) {
|
|
78
|
+
pages.push({
|
|
79
|
+
items: blogPosts
|
|
80
|
+
.slice(page * postsPerPage, (page + 1) * postsPerPage)
|
|
81
|
+
.map((item) => item.id),
|
|
82
|
+
metadata: {
|
|
83
|
+
permalink: permalink(page),
|
|
84
|
+
page: page + 1,
|
|
85
|
+
postsPerPage,
|
|
86
|
+
totalPages: numberOfPages,
|
|
87
|
+
totalCount,
|
|
88
|
+
previousPage: page !== 0 ? permalink(page - 1) : undefined,
|
|
89
|
+
nextPage: page < numberOfPages - 1 ? permalink(page + 1) : undefined,
|
|
90
|
+
blogDescription,
|
|
91
|
+
blogTitle,
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return pages;
|
|
56
97
|
}
|
|
57
98
|
|
|
58
|
-
function
|
|
99
|
+
export function getBlogTags({
|
|
100
|
+
blogPosts,
|
|
101
|
+
...params
|
|
102
|
+
}: {
|
|
103
|
+
blogPosts: BlogPost[];
|
|
104
|
+
blogTitle: string;
|
|
105
|
+
blogDescription: string;
|
|
106
|
+
postsPerPageOption: number | 'ALL';
|
|
107
|
+
}): BlogTags {
|
|
108
|
+
const groups = groupTaggedItems(
|
|
109
|
+
blogPosts,
|
|
110
|
+
(blogPost) => blogPost.metadata.tags,
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
return _.mapValues(groups, ({tag, items: tagBlogPosts}) => ({
|
|
114
|
+
label: tag.label,
|
|
115
|
+
items: tagBlogPosts.map((item) => item.id),
|
|
116
|
+
permalink: tag.permalink,
|
|
117
|
+
pages: paginateBlogPosts({
|
|
118
|
+
blogPosts: tagBlogPosts,
|
|
119
|
+
basePageUrl: tag.permalink,
|
|
120
|
+
...params,
|
|
121
|
+
}),
|
|
122
|
+
}));
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const DATE_FILENAME_REGEX =
|
|
126
|
+
/^(?<folder>.*)(?<date>\d{4}[-/]\d{1,2}[-/]\d{1,2})[-/]?(?<text>.*?)(?:\/index)?.mdx?$/;
|
|
127
|
+
|
|
128
|
+
type ParsedBlogFileName = {
|
|
129
|
+
date: Date | undefined;
|
|
130
|
+
text: string;
|
|
131
|
+
slug: string;
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
export function parseBlogFileName(
|
|
135
|
+
blogSourceRelative: string,
|
|
136
|
+
): ParsedBlogFileName {
|
|
137
|
+
const dateFilenameMatch = blogSourceRelative.match(DATE_FILENAME_REGEX);
|
|
138
|
+
if (dateFilenameMatch) {
|
|
139
|
+
const {folder, text, date: dateString} = dateFilenameMatch.groups!;
|
|
140
|
+
// Always treat dates as UTC by adding the `Z`
|
|
141
|
+
const date = new Date(`${dateString!}Z`);
|
|
142
|
+
const slugDate = dateString!.replace(/-/g, '/');
|
|
143
|
+
const slug = `/${slugDate}/${folder!}${text!}`;
|
|
144
|
+
return {date, text: text!, slug};
|
|
145
|
+
}
|
|
146
|
+
const text = blogSourceRelative.replace(/(?:\/index)?\.mdx?$/, '');
|
|
147
|
+
const slug = `/${text}`;
|
|
148
|
+
return {date: undefined, text, slug};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function formatBlogPostDate(
|
|
152
|
+
locale: string,
|
|
153
|
+
date: Date,
|
|
154
|
+
calendar: string,
|
|
155
|
+
): string {
|
|
59
156
|
try {
|
|
60
157
|
return new Intl.DateTimeFormat(locale, {
|
|
61
158
|
day: 'numeric',
|
|
62
159
|
month: 'long',
|
|
63
160
|
year: 'numeric',
|
|
64
161
|
timeZone: 'UTC',
|
|
162
|
+
calendar,
|
|
65
163
|
}).format(date);
|
|
66
|
-
} catch (
|
|
67
|
-
|
|
164
|
+
} catch (err) {
|
|
165
|
+
logger.error`Can't format blog post date "${String(date)}"`;
|
|
166
|
+
throw err;
|
|
68
167
|
}
|
|
69
168
|
}
|
|
70
169
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
if (!options.feedOptions) {
|
|
77
|
-
throw new Error(
|
|
78
|
-
'Invalid options: "feedOptions" is not expected to be null.',
|
|
79
|
-
);
|
|
80
|
-
}
|
|
81
|
-
const {siteConfig} = context;
|
|
82
|
-
const blogPosts = await generateBlogPosts(contentPaths, context, options);
|
|
83
|
-
if (!blogPosts.length) {
|
|
84
|
-
return null;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const {feedOptions, routeBasePath} = options;
|
|
88
|
-
const {url: siteUrl, baseUrl, title, favicon} = siteConfig;
|
|
89
|
-
const blogBaseUrl = normalizeUrl([siteUrl, baseUrl, routeBasePath]);
|
|
90
|
-
|
|
91
|
-
const updated =
|
|
92
|
-
(blogPosts[0] && blogPosts[0].metadata.date) ||
|
|
93
|
-
new Date('2015-10-25T16:29:00.000-07:00');
|
|
94
|
-
|
|
95
|
-
const feed = new Feed({
|
|
96
|
-
id: blogBaseUrl,
|
|
97
|
-
title: feedOptions.title || `${title} Blog`,
|
|
98
|
-
updated,
|
|
99
|
-
language: feedOptions.language,
|
|
100
|
-
link: blogBaseUrl,
|
|
101
|
-
description: feedOptions.description || `${siteConfig.title} Blog`,
|
|
102
|
-
favicon: favicon ? normalizeUrl([siteUrl, baseUrl, favicon]) : undefined,
|
|
103
|
-
copyright: feedOptions.copyright,
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
blogPosts.forEach((post) => {
|
|
107
|
-
const {
|
|
108
|
-
id,
|
|
109
|
-
metadata: {title: metadataTitle, permalink, date, description},
|
|
110
|
-
} = post;
|
|
111
|
-
feed.addItem({
|
|
112
|
-
title: metadataTitle,
|
|
113
|
-
id,
|
|
114
|
-
link: normalizeUrl([siteUrl, permalink]),
|
|
115
|
-
date,
|
|
116
|
-
description,
|
|
170
|
+
async function parseBlogPostMarkdownFile(blogSourceAbsolute: string) {
|
|
171
|
+
const markdownString = await fs.readFile(blogSourceAbsolute, 'utf-8');
|
|
172
|
+
try {
|
|
173
|
+
const result = parseMarkdownString(markdownString, {
|
|
174
|
+
removeContentTitle: true,
|
|
117
175
|
});
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
176
|
+
return {
|
|
177
|
+
...result,
|
|
178
|
+
frontMatter: validateBlogPostFrontMatter(result.frontMatter),
|
|
179
|
+
};
|
|
180
|
+
} catch (err) {
|
|
181
|
+
logger.error`Error while parsing blog post file path=${blogSourceAbsolute}.`;
|
|
182
|
+
throw err;
|
|
183
|
+
}
|
|
121
184
|
}
|
|
122
185
|
|
|
123
|
-
|
|
186
|
+
const defaultReadingTime: ReadingTimeFunction = ({content, options}) =>
|
|
187
|
+
readingTime(content, options).minutes;
|
|
188
|
+
|
|
189
|
+
async function processBlogSourceFile(
|
|
190
|
+
blogSourceRelative: string,
|
|
124
191
|
contentPaths: BlogContentPaths,
|
|
125
|
-
|
|
192
|
+
context: LoadContext,
|
|
126
193
|
options: PluginOptions,
|
|
127
|
-
|
|
194
|
+
authorsMap?: AuthorsMap,
|
|
195
|
+
): Promise<BlogPost | undefined> {
|
|
196
|
+
const {
|
|
197
|
+
siteConfig: {baseUrl},
|
|
198
|
+
siteDir,
|
|
199
|
+
i18n,
|
|
200
|
+
} = context;
|
|
128
201
|
const {
|
|
129
|
-
include,
|
|
130
|
-
exclude,
|
|
131
202
|
routeBasePath,
|
|
203
|
+
tagsBasePath: tagsRouteBasePath,
|
|
132
204
|
truncateMarker,
|
|
133
205
|
showReadingTime,
|
|
134
206
|
editUrl,
|
|
135
207
|
} = options;
|
|
136
208
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
209
|
+
// Lookup in localized folder in priority
|
|
210
|
+
const blogDirPath = await getFolderContainingFile(
|
|
211
|
+
getContentPathList(contentPaths),
|
|
212
|
+
blogSourceRelative,
|
|
213
|
+
);
|
|
140
214
|
|
|
141
|
-
const
|
|
142
|
-
const blogSourceFiles = await Globby(include, {
|
|
143
|
-
cwd: contentPaths.contentPath,
|
|
144
|
-
ignore: exclude,
|
|
145
|
-
});
|
|
215
|
+
const blogSourceAbsolute = path.join(blogDirPath, blogSourceRelative);
|
|
146
216
|
|
|
147
|
-
const
|
|
217
|
+
const {frontMatter, content, contentTitle, excerpt} =
|
|
218
|
+
await parseBlogPostMarkdownFile(blogSourceAbsolute);
|
|
148
219
|
|
|
149
|
-
|
|
150
|
-
// Lookup in localized folder in priority
|
|
151
|
-
const blogDirPath = await getFolderContainingFile(
|
|
152
|
-
getContentPathList(contentPaths),
|
|
153
|
-
blogSourceFile,
|
|
154
|
-
);
|
|
220
|
+
const aliasedSource = aliasedSitePath(blogSourceAbsolute, siteDir);
|
|
155
221
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
frontMatter: unsafeFrontMatter,
|
|
160
|
-
content,
|
|
161
|
-
contentTitle,
|
|
162
|
-
excerpt,
|
|
163
|
-
} = await parseMarkdownFile(source, {removeContentTitle: true});
|
|
164
|
-
const frontMatter = validateBlogPostFrontMatter(unsafeFrontMatter);
|
|
222
|
+
if (frontMatter.draft && process.env.NODE_ENV === 'production') {
|
|
223
|
+
return undefined;
|
|
224
|
+
}
|
|
165
225
|
|
|
166
|
-
|
|
226
|
+
if (frontMatter.id) {
|
|
227
|
+
logger.warn`name=${'id'} header option is deprecated in path=${blogSourceRelative} file. Please use name=${'slug'} option instead.`;
|
|
228
|
+
}
|
|
167
229
|
|
|
168
|
-
|
|
230
|
+
const parsedBlogFileName = parseBlogFileName(blogSourceRelative);
|
|
169
231
|
|
|
170
|
-
|
|
171
|
-
|
|
232
|
+
async function getDate(): Promise<Date> {
|
|
233
|
+
// Prefer user-defined date.
|
|
234
|
+
if (frontMatter.date) {
|
|
235
|
+
if (typeof frontMatter.date === 'string') {
|
|
236
|
+
// Always treat dates as UTC by adding the `Z`
|
|
237
|
+
return new Date(`${frontMatter.date}Z`);
|
|
238
|
+
}
|
|
239
|
+
// YAML only converts YYYY-MM-DD to dates and leaves others as strings.
|
|
240
|
+
return frontMatter.date;
|
|
241
|
+
} else if (parsedBlogFileName.date) {
|
|
242
|
+
return parsedBlogFileName.date;
|
|
172
243
|
}
|
|
173
244
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
245
|
+
try {
|
|
246
|
+
const result = getFileCommitDate(blogSourceAbsolute, {
|
|
247
|
+
age: 'oldest',
|
|
248
|
+
includeAuthor: false,
|
|
249
|
+
});
|
|
250
|
+
return result.date;
|
|
251
|
+
} catch (err) {
|
|
252
|
+
logger.warn(err);
|
|
253
|
+
return (await fs.stat(blogSourceAbsolute)).birthtime;
|
|
180
254
|
}
|
|
255
|
+
}
|
|
181
256
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
257
|
+
const date = await getDate();
|
|
258
|
+
const formattedDate = formatBlogPostDate(
|
|
259
|
+
i18n.currentLocale,
|
|
260
|
+
date,
|
|
261
|
+
i18n.localeConfigs[i18n.currentLocale]!.calendar,
|
|
262
|
+
);
|
|
186
263
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
// Always treat dates as UTC by adding the `Z`
|
|
190
|
-
date = new Date(`${dateString}Z`);
|
|
191
|
-
linkName = name;
|
|
192
|
-
}
|
|
264
|
+
const title = frontMatter.title ?? contentTitle ?? parsedBlogFileName.text;
|
|
265
|
+
const description = frontMatter.description ?? excerpt ?? '';
|
|
193
266
|
|
|
194
|
-
|
|
195
|
-
if (frontMatter.date) {
|
|
196
|
-
date = new Date(frontMatter.date);
|
|
197
|
-
}
|
|
267
|
+
const slug = frontMatter.slug ?? parsedBlogFileName.slug;
|
|
198
268
|
|
|
199
|
-
|
|
200
|
-
date = date ?? (await fs.stat(source)).birthtime;
|
|
201
|
-
const formattedDate = formatBlogPostDate(i18n.currentLocale, date);
|
|
202
|
-
|
|
203
|
-
const title = frontMatter.title ?? contentTitle ?? linkName;
|
|
204
|
-
const description = frontMatter.description ?? excerpt ?? '';
|
|
205
|
-
|
|
206
|
-
const slug =
|
|
207
|
-
frontMatter.slug ||
|
|
208
|
-
(dateFilenameMatch ? toUrl({date, link: linkName}) : linkName);
|
|
209
|
-
|
|
210
|
-
const permalink = normalizeUrl([baseUrl, routeBasePath, slug]);
|
|
211
|
-
|
|
212
|
-
function getBlogEditUrl() {
|
|
213
|
-
const blogPathRelative = path.relative(blogDirPath, path.resolve(source));
|
|
214
|
-
|
|
215
|
-
if (typeof editUrl === 'function') {
|
|
216
|
-
return editUrl({
|
|
217
|
-
blogDirPath: posixPath(path.relative(siteDir, blogDirPath)),
|
|
218
|
-
blogPath: posixPath(blogPathRelative),
|
|
219
|
-
permalink,
|
|
220
|
-
locale: i18n.currentLocale,
|
|
221
|
-
});
|
|
222
|
-
} else if (typeof editUrl === 'string') {
|
|
223
|
-
const isLocalized = blogDirPath === contentPaths.contentPathLocalized;
|
|
224
|
-
const fileContentPath =
|
|
225
|
-
isLocalized && options.editLocalizedFiles
|
|
226
|
-
? contentPaths.contentPathLocalized
|
|
227
|
-
: contentPaths.contentPath;
|
|
228
|
-
|
|
229
|
-
const contentPathEditUrl = normalizeUrl([
|
|
230
|
-
editUrl,
|
|
231
|
-
posixPath(path.relative(siteDir, fileContentPath)),
|
|
232
|
-
]);
|
|
233
|
-
|
|
234
|
-
return getEditUrl(blogPathRelative, contentPathEditUrl);
|
|
235
|
-
} else {
|
|
236
|
-
return undefined;
|
|
237
|
-
}
|
|
238
|
-
}
|
|
269
|
+
const permalink = normalizeUrl([baseUrl, routeBasePath, slug]);
|
|
239
270
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
271
|
+
function getBlogEditUrl() {
|
|
272
|
+
const blogPathRelative = path.relative(
|
|
273
|
+
blogDirPath,
|
|
274
|
+
path.resolve(blogSourceAbsolute),
|
|
275
|
+
);
|
|
276
|
+
|
|
277
|
+
if (typeof editUrl === 'function') {
|
|
278
|
+
return editUrl({
|
|
279
|
+
blogDirPath: posixPath(path.relative(siteDir, blogDirPath)),
|
|
280
|
+
blogPath: posixPath(blogPathRelative),
|
|
243
281
|
permalink,
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
282
|
+
locale: i18n.currentLocale,
|
|
283
|
+
});
|
|
284
|
+
} else if (typeof editUrl === 'string') {
|
|
285
|
+
const isLocalized = blogDirPath === contentPaths.contentPathLocalized;
|
|
286
|
+
const fileContentPath =
|
|
287
|
+
isLocalized && options.editLocalizedFiles
|
|
288
|
+
? contentPaths.contentPathLocalized
|
|
289
|
+
: contentPaths.contentPath;
|
|
290
|
+
|
|
291
|
+
const contentPathEditUrl = normalizeUrl([
|
|
292
|
+
editUrl,
|
|
293
|
+
posixPath(path.relative(siteDir, fileContentPath)),
|
|
294
|
+
]);
|
|
295
|
+
|
|
296
|
+
return getEditUrl(blogPathRelative, contentPathEditUrl);
|
|
297
|
+
}
|
|
298
|
+
return undefined;
|
|
255
299
|
}
|
|
256
300
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
301
|
+
const tagsBasePath = normalizeUrl([
|
|
302
|
+
baseUrl,
|
|
303
|
+
routeBasePath,
|
|
304
|
+
tagsRouteBasePath,
|
|
305
|
+
]);
|
|
306
|
+
const authors = getBlogPostAuthors({authorsMap, frontMatter});
|
|
307
|
+
|
|
308
|
+
return {
|
|
309
|
+
id: slug,
|
|
310
|
+
metadata: {
|
|
311
|
+
permalink,
|
|
312
|
+
editUrl: getBlogEditUrl(),
|
|
313
|
+
source: aliasedSource,
|
|
314
|
+
title,
|
|
315
|
+
description,
|
|
316
|
+
date,
|
|
317
|
+
formattedDate,
|
|
318
|
+
tags: normalizeFrontMatterTags(tagsBasePath, frontMatter.tags),
|
|
319
|
+
readingTime: showReadingTime
|
|
320
|
+
? options.readingTime({
|
|
321
|
+
content,
|
|
322
|
+
frontMatter,
|
|
323
|
+
defaultReadingTime,
|
|
324
|
+
})
|
|
325
|
+
: undefined,
|
|
326
|
+
hasTruncateMarker: truncateMarker.test(content),
|
|
327
|
+
authors,
|
|
328
|
+
frontMatter,
|
|
329
|
+
},
|
|
330
|
+
content,
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
export async function generateBlogPosts(
|
|
335
|
+
contentPaths: BlogContentPaths,
|
|
336
|
+
context: LoadContext,
|
|
337
|
+
options: PluginOptions,
|
|
338
|
+
): Promise<BlogPost[]> {
|
|
339
|
+
const {include, exclude} = options;
|
|
340
|
+
|
|
341
|
+
if (!(await fs.pathExists(contentPaths.contentPath))) {
|
|
342
|
+
return [];
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
const blogSourceFiles = await Globby(include, {
|
|
346
|
+
cwd: contentPaths.contentPath,
|
|
347
|
+
ignore: exclude,
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
const authorsMap = await getAuthorsMap({
|
|
351
|
+
contentPaths,
|
|
352
|
+
authorsMapPath: options.authorsMapPath,
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
const blogPosts = (
|
|
356
|
+
await Promise.all(
|
|
357
|
+
blogSourceFiles.map(async (blogSourceFile: string) => {
|
|
358
|
+
try {
|
|
359
|
+
return await processBlogSourceFile(
|
|
360
|
+
blogSourceFile,
|
|
361
|
+
contentPaths,
|
|
362
|
+
context,
|
|
363
|
+
options,
|
|
364
|
+
authorsMap,
|
|
365
|
+
);
|
|
366
|
+
} catch (err) {
|
|
367
|
+
logger.error`Processing of blog source file path=${blogSourceFile} failed.`;
|
|
368
|
+
throw err;
|
|
369
|
+
}
|
|
370
|
+
}),
|
|
371
|
+
)
|
|
372
|
+
).filter(Boolean) as BlogPost[];
|
|
271
373
|
|
|
272
374
|
blogPosts.sort(
|
|
273
375
|
(a, b) => b.metadata.date.getTime() - a.metadata.date.getTime(),
|
|
274
376
|
);
|
|
275
377
|
|
|
378
|
+
if (options.sortPosts === 'ascending') {
|
|
379
|
+
return blogPosts.reverse();
|
|
380
|
+
}
|
|
276
381
|
return blogPosts;
|
|
277
382
|
}
|
|
278
383
|
|
|
@@ -304,8 +409,3 @@ export function linkify({
|
|
|
304
409
|
|
|
305
410
|
return newContent;
|
|
306
411
|
}
|
|
307
|
-
|
|
308
|
-
// Order matters: we look in priority in localized folder
|
|
309
|
-
export function getContentPathList(contentPaths: BlogContentPaths): string[] {
|
|
310
|
-
return [contentPaths.contentPathLocalized, contentPaths.contentPath];
|
|
311
|
-
}
|