@docusaurus/plugin-content-blog 2.0.0-beta.1ab8aa0af → 2.0.0-beta.2
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 -4403
- package/lib/blogFrontMatter.js +5 -5
- package/lib/blogUtils.js +34 -17
- package/lib/index.d.ts +1 -1
- package/lib/index.js +23 -13
- package/package.json +12 -11
- package/src/__tests__/__snapshots__/generateBlogFeed.test.ts.snap +12 -37
- package/src/__tests__/blogFrontMatter.test.ts +84 -32
- package/src/__tests__/generateBlogFeed.test.ts +2 -2
- package/src/blogFrontMatter.ts +6 -5
- package/src/blogUtils.ts +124 -106
- package/src/index.ts +31 -14
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
BlogPostFrontMatter,
|
|
10
10
|
validateBlogPostFrontMatter,
|
|
11
11
|
} from '../blogFrontMatter';
|
|
12
|
+
import escapeStringRegexp from 'escape-string-regexp';
|
|
12
13
|
|
|
13
14
|
function testField(params: {
|
|
14
15
|
fieldName: keyof BlogPostFrontMatter;
|
|
@@ -41,7 +42,20 @@ function testField(params: {
|
|
|
41
42
|
|
|
42
43
|
test('throw error for values', () => {
|
|
43
44
|
params.invalidFrontMatters?.forEach(([frontMatter, message]) => {
|
|
44
|
-
|
|
45
|
+
try {
|
|
46
|
+
validateBlogPostFrontMatter(frontMatter);
|
|
47
|
+
fail(
|
|
48
|
+
new Error(
|
|
49
|
+
`Blog frontmatter is expected to be rejected, but was accepted successfully:\n ${JSON.stringify(
|
|
50
|
+
frontMatter,
|
|
51
|
+
null,
|
|
52
|
+
2,
|
|
53
|
+
)}`,
|
|
54
|
+
),
|
|
55
|
+
);
|
|
56
|
+
} catch (e) {
|
|
57
|
+
expect(e.message).toMatch(new RegExp(escapeStringRegexp(message)));
|
|
58
|
+
}
|
|
45
59
|
});
|
|
46
60
|
});
|
|
47
61
|
});
|
|
@@ -57,7 +71,9 @@ describe('validateBlogPostFrontMatter', () => {
|
|
|
57
71
|
const frontMatter = {abc: '1'};
|
|
58
72
|
expect(validateBlogPostFrontMatter(frontMatter)).toEqual(frontMatter);
|
|
59
73
|
});
|
|
74
|
+
});
|
|
60
75
|
|
|
76
|
+
describe('validateBlogPostFrontMatter description', () => {
|
|
61
77
|
testField({
|
|
62
78
|
fieldName: 'description',
|
|
63
79
|
validFrontMatters: [
|
|
@@ -66,7 +82,9 @@ describe('validateBlogPostFrontMatter', () => {
|
|
|
66
82
|
{description: 'description'},
|
|
67
83
|
],
|
|
68
84
|
});
|
|
85
|
+
});
|
|
69
86
|
|
|
87
|
+
describe('validateBlogPostFrontMatter title', () => {
|
|
70
88
|
testField({
|
|
71
89
|
fieldName: 'title',
|
|
72
90
|
validFrontMatters: [
|
|
@@ -75,25 +93,25 @@ describe('validateBlogPostFrontMatter', () => {
|
|
|
75
93
|
{title: 'title'},
|
|
76
94
|
],
|
|
77
95
|
});
|
|
96
|
+
});
|
|
78
97
|
|
|
98
|
+
describe('validateBlogPostFrontMatter id', () => {
|
|
79
99
|
testField({
|
|
80
100
|
fieldName: 'id',
|
|
81
101
|
validFrontMatters: [{id: '123'}, {id: 'id'}],
|
|
82
102
|
invalidFrontMatters: [[{id: ''}, 'is not allowed to be empty']],
|
|
83
103
|
});
|
|
104
|
+
});
|
|
84
105
|
|
|
106
|
+
describe('validateBlogPostFrontMatter author', () => {
|
|
85
107
|
testField({
|
|
86
108
|
fieldName: 'author',
|
|
87
109
|
validFrontMatters: [{author: '123'}, {author: 'author'}],
|
|
88
110
|
invalidFrontMatters: [[{author: ''}, 'is not allowed to be empty']],
|
|
89
111
|
});
|
|
112
|
+
});
|
|
90
113
|
|
|
91
|
-
|
|
92
|
-
fieldName: 'authorTitle',
|
|
93
|
-
validFrontMatters: [{authorTitle: '123'}, {authorTitle: 'authorTitle'}],
|
|
94
|
-
invalidFrontMatters: [[{authorTitle: ''}, 'is not allowed to be empty']],
|
|
95
|
-
});
|
|
96
|
-
|
|
114
|
+
describe('validateBlogPostFrontMatter author_title', () => {
|
|
97
115
|
testField({
|
|
98
116
|
fieldName: 'author_title',
|
|
99
117
|
validFrontMatters: [{author_title: '123'}, {author_title: 'author_title'}],
|
|
@@ -101,49 +119,75 @@ describe('validateBlogPostFrontMatter', () => {
|
|
|
101
119
|
});
|
|
102
120
|
|
|
103
121
|
testField({
|
|
104
|
-
fieldName: '
|
|
105
|
-
validFrontMatters: [{
|
|
106
|
-
invalidFrontMatters: [
|
|
107
|
-
[{authorURL: ''}, 'is not allowed to be empty'],
|
|
108
|
-
[{authorURL: '@site/api/author'}, 'must be a valid uri'],
|
|
109
|
-
[{authorURL: '../../api/author'}, 'must be a valid uri'],
|
|
110
|
-
],
|
|
122
|
+
fieldName: 'authorTitle',
|
|
123
|
+
validFrontMatters: [{authorTitle: '123'}, {authorTitle: 'authorTitle'}],
|
|
124
|
+
invalidFrontMatters: [[{authorTitle: ''}, 'is not allowed to be empty']],
|
|
111
125
|
});
|
|
126
|
+
});
|
|
112
127
|
|
|
128
|
+
describe('validateBlogPostFrontMatter author_url', () => {
|
|
113
129
|
testField({
|
|
114
130
|
fieldName: 'author_url',
|
|
115
|
-
validFrontMatters: [
|
|
131
|
+
validFrontMatters: [
|
|
132
|
+
{author_url: 'https://docusaurus.io'},
|
|
133
|
+
{author_url: '../../relative'},
|
|
134
|
+
{author_url: '/absolute'},
|
|
135
|
+
],
|
|
116
136
|
invalidFrontMatters: [
|
|
117
|
-
[
|
|
118
|
-
|
|
119
|
-
|
|
137
|
+
[
|
|
138
|
+
{author_url: ''},
|
|
139
|
+
'"author_url" does not match any of the allowed types',
|
|
140
|
+
],
|
|
120
141
|
],
|
|
121
142
|
});
|
|
122
143
|
|
|
123
144
|
testField({
|
|
124
|
-
fieldName: '
|
|
145
|
+
fieldName: 'authorURL',
|
|
125
146
|
validFrontMatters: [
|
|
126
|
-
{
|
|
147
|
+
{authorURL: 'https://docusaurus.io'},
|
|
148
|
+
{authorURL: '../../relative'},
|
|
149
|
+
{authorURL: '/absolute'},
|
|
127
150
|
],
|
|
151
|
+
|
|
128
152
|
invalidFrontMatters: [
|
|
129
|
-
[{
|
|
130
|
-
[{authorImageURL: '@site/api/asset/image.png'}, 'must be a valid uri'],
|
|
131
|
-
[{authorImageURL: '../../api/asset/image.png'}, 'must be a valid uri'],
|
|
153
|
+
[{authorURL: ''}, '"authorURL" does not match any of the allowed types'],
|
|
132
154
|
],
|
|
133
155
|
});
|
|
156
|
+
});
|
|
134
157
|
|
|
158
|
+
describe('validateBlogPostFrontMatter author_image_url', () => {
|
|
135
159
|
testField({
|
|
136
160
|
fieldName: 'author_image_url',
|
|
137
161
|
validFrontMatters: [
|
|
138
162
|
{author_image_url: 'https://docusaurus.io/asset/image.png'},
|
|
163
|
+
{author_image_url: '../../relative'},
|
|
164
|
+
{author_image_url: '/absolute'},
|
|
139
165
|
],
|
|
140
166
|
invalidFrontMatters: [
|
|
141
|
-
[
|
|
142
|
-
|
|
143
|
-
|
|
167
|
+
[
|
|
168
|
+
{author_image_url: ''},
|
|
169
|
+
'"author_image_url" does not match any of the allowed types',
|
|
170
|
+
],
|
|
144
171
|
],
|
|
145
172
|
});
|
|
146
173
|
|
|
174
|
+
testField({
|
|
175
|
+
fieldName: 'authorImageURL',
|
|
176
|
+
validFrontMatters: [
|
|
177
|
+
{authorImageURL: 'https://docusaurus.io/asset/image.png'},
|
|
178
|
+
{authorImageURL: '../../relative'},
|
|
179
|
+
{authorImageURL: '/absolute'},
|
|
180
|
+
],
|
|
181
|
+
invalidFrontMatters: [
|
|
182
|
+
[
|
|
183
|
+
{authorImageURL: ''},
|
|
184
|
+
'"authorImageURL" does not match any of the allowed types',
|
|
185
|
+
],
|
|
186
|
+
],
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
describe('validateBlogPostFrontMatter slug', () => {
|
|
147
191
|
testField({
|
|
148
192
|
fieldName: 'slug',
|
|
149
193
|
validFrontMatters: [
|
|
@@ -158,10 +202,13 @@ describe('validateBlogPostFrontMatter', () => {
|
|
|
158
202
|
],
|
|
159
203
|
invalidFrontMatters: [[{slug: ''}, 'is not allowed to be empty']],
|
|
160
204
|
});
|
|
205
|
+
});
|
|
161
206
|
|
|
207
|
+
describe('validateBlogPostFrontMatter image', () => {
|
|
162
208
|
testField({
|
|
163
209
|
fieldName: 'image',
|
|
164
210
|
validFrontMatters: [
|
|
211
|
+
{image: 'https://docusaurus.io/image.png'},
|
|
165
212
|
{image: 'blog/'},
|
|
166
213
|
{image: '/blog'},
|
|
167
214
|
{image: '/blog/'},
|
|
@@ -172,15 +219,12 @@ describe('validateBlogPostFrontMatter', () => {
|
|
|
172
219
|
{image: '@site/api/asset/image.png'},
|
|
173
220
|
],
|
|
174
221
|
invalidFrontMatters: [
|
|
175
|
-
[{image: ''}, '
|
|
176
|
-
[{image: 'https://docusaurus.io'}, 'must be a valid relative uri'],
|
|
177
|
-
[
|
|
178
|
-
{image: 'https://docusaurus.io/blog/image.png'},
|
|
179
|
-
'must be a valid relative uri',
|
|
180
|
-
],
|
|
222
|
+
[{image: ''}, '"image" does not match any of the allowed types'],
|
|
181
223
|
],
|
|
182
224
|
});
|
|
225
|
+
});
|
|
183
226
|
|
|
227
|
+
describe('validateBlogPostFrontMatter tags', () => {
|
|
184
228
|
testField({
|
|
185
229
|
fieldName: 'tags',
|
|
186
230
|
validFrontMatters: [
|
|
@@ -203,7 +247,9 @@ describe('validateBlogPostFrontMatter', () => {
|
|
|
203
247
|
],
|
|
204
248
|
],
|
|
205
249
|
});
|
|
250
|
+
});
|
|
206
251
|
|
|
252
|
+
describe('validateBlogPostFrontMatter keywords', () => {
|
|
207
253
|
testField({
|
|
208
254
|
fieldName: 'keywords',
|
|
209
255
|
validFrontMatters: [
|
|
@@ -218,7 +264,9 @@ describe('validateBlogPostFrontMatter', () => {
|
|
|
218
264
|
[{keywords: []}, 'does not contain 1 required value(s)'],
|
|
219
265
|
],
|
|
220
266
|
});
|
|
267
|
+
});
|
|
221
268
|
|
|
269
|
+
describe('validateBlogPostFrontMatter draft', () => {
|
|
222
270
|
testField({
|
|
223
271
|
fieldName: 'draft',
|
|
224
272
|
validFrontMatters: [{draft: true}, {draft: false}],
|
|
@@ -231,7 +279,9 @@ describe('validateBlogPostFrontMatter', () => {
|
|
|
231
279
|
[{draft: 'no'}, 'must be a boolean'],
|
|
232
280
|
],
|
|
233
281
|
});
|
|
282
|
+
});
|
|
234
283
|
|
|
284
|
+
describe('validateBlogPostFrontMatter hide_table_of_contents', () => {
|
|
235
285
|
testField({
|
|
236
286
|
fieldName: 'hide_table_of_contents',
|
|
237
287
|
validFrontMatters: [
|
|
@@ -247,7 +297,9 @@ describe('validateBlogPostFrontMatter', () => {
|
|
|
247
297
|
[{hide_table_of_contents: 'no'}, 'must be a boolean'],
|
|
248
298
|
],
|
|
249
299
|
});
|
|
300
|
+
});
|
|
250
301
|
|
|
302
|
+
describe('validateBlogPostFrontMatter date', () => {
|
|
251
303
|
testField({
|
|
252
304
|
fieldName: 'date',
|
|
253
305
|
validFrontMatters: [
|
|
@@ -32,7 +32,7 @@ function getBlogContentPaths(siteDir: string): BlogContentPaths {
|
|
|
32
32
|
describe('blogFeed', () => {
|
|
33
33
|
(['atom', 'rss'] as const).forEach((feedType) => {
|
|
34
34
|
describe(`${feedType}`, () => {
|
|
35
|
-
test('
|
|
35
|
+
test('should not show feed without posts', async () => {
|
|
36
36
|
const siteDir = __dirname;
|
|
37
37
|
const siteConfig = {
|
|
38
38
|
title: 'Hello',
|
|
@@ -68,7 +68,7 @@ describe('blogFeed', () => {
|
|
|
68
68
|
const generatedFilesDir = path.resolve(siteDir, '.docusaurus');
|
|
69
69
|
const siteConfig = {
|
|
70
70
|
title: 'Hello',
|
|
71
|
-
baseUrl: '/',
|
|
71
|
+
baseUrl: '/myBaseUrl/',
|
|
72
72
|
url: 'https://docusaurus.io',
|
|
73
73
|
favicon: 'image/favicon.ico',
|
|
74
74
|
};
|
package/src/blogFrontMatter.ts
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
import {
|
|
11
11
|
JoiFrontMatter as Joi, // Custom instance for frontmatter
|
|
12
|
+
URISchema,
|
|
12
13
|
validateFrontMatter,
|
|
13
14
|
} from '@docusaurus/utils-validation';
|
|
14
15
|
import {Tag} from './types';
|
|
@@ -59,19 +60,19 @@ const BlogFrontMatterSchema = Joi.object<BlogPostFrontMatter>({
|
|
|
59
60
|
|
|
60
61
|
author: Joi.string(),
|
|
61
62
|
author_title: Joi.string(),
|
|
62
|
-
author_url:
|
|
63
|
-
author_image_url:
|
|
63
|
+
author_url: URISchema,
|
|
64
|
+
author_image_url: URISchema,
|
|
64
65
|
slug: Joi.string(),
|
|
65
|
-
image:
|
|
66
|
+
image: URISchema,
|
|
66
67
|
keywords: Joi.array().items(Joi.string().required()),
|
|
67
68
|
hide_table_of_contents: Joi.boolean(),
|
|
68
69
|
|
|
69
70
|
// TODO re-enable warnings later, our v1 blog posts use those older frontmatter fields
|
|
70
|
-
authorURL:
|
|
71
|
+
authorURL: URISchema,
|
|
71
72
|
// .warning('deprecate.error', { alternative: '"author_url"'}),
|
|
72
73
|
authorTitle: Joi.string(),
|
|
73
74
|
// .warning('deprecate.error', { alternative: '"author_title"'}),
|
|
74
|
-
authorImageURL:
|
|
75
|
+
authorImageURL: URISchema,
|
|
75
76
|
// .warning('deprecate.error', { alternative: '"author_image_url"'}),
|
|
76
77
|
})
|
|
77
78
|
.unknown()
|
package/src/blogUtils.ts
CHANGED
|
@@ -55,6 +55,19 @@ function toUrl({date, link}: DateLink) {
|
|
|
55
55
|
.replace(/-/g, '/')}/${link}`;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
function formatBlogPostDate(locale: string, date: Date): string {
|
|
59
|
+
try {
|
|
60
|
+
return new Intl.DateTimeFormat(locale, {
|
|
61
|
+
day: 'numeric',
|
|
62
|
+
month: 'long',
|
|
63
|
+
year: 'numeric',
|
|
64
|
+
timeZone: 'UTC',
|
|
65
|
+
}).format(date);
|
|
66
|
+
} catch (e) {
|
|
67
|
+
throw new Error(`Can't format blog post date "${date}"`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
58
71
|
export async function generateBlogFeed(
|
|
59
72
|
contentPaths: BlogContentPaths,
|
|
60
73
|
context: LoadContext,
|
|
@@ -62,18 +75,18 @@ export async function generateBlogFeed(
|
|
|
62
75
|
): Promise<Feed | null> {
|
|
63
76
|
if (!options.feedOptions) {
|
|
64
77
|
throw new Error(
|
|
65
|
-
'Invalid options
|
|
78
|
+
'Invalid options: "feedOptions" is not expected to be null.',
|
|
66
79
|
);
|
|
67
80
|
}
|
|
68
81
|
const {siteConfig} = context;
|
|
69
82
|
const blogPosts = await generateBlogPosts(contentPaths, context, options);
|
|
70
|
-
if (blogPosts
|
|
83
|
+
if (!blogPosts.length) {
|
|
71
84
|
return null;
|
|
72
85
|
}
|
|
73
86
|
|
|
74
87
|
const {feedOptions, routeBasePath} = options;
|
|
75
|
-
const {url: siteUrl, title, favicon} = siteConfig;
|
|
76
|
-
const blogBaseUrl = normalizeUrl([siteUrl, routeBasePath]);
|
|
88
|
+
const {url: siteUrl, baseUrl, title, favicon} = siteConfig;
|
|
89
|
+
const blogBaseUrl = normalizeUrl([siteUrl, baseUrl, routeBasePath]);
|
|
77
90
|
|
|
78
91
|
const updated =
|
|
79
92
|
(blogPosts[0] && blogPosts[0].metadata.date) ||
|
|
@@ -86,7 +99,7 @@ export async function generateBlogFeed(
|
|
|
86
99
|
language: feedOptions.language,
|
|
87
100
|
link: blogBaseUrl,
|
|
88
101
|
description: feedOptions.description || `${siteConfig.title} Blog`,
|
|
89
|
-
favicon: normalizeUrl([siteUrl, favicon]),
|
|
102
|
+
favicon: favicon ? normalizeUrl([siteUrl, baseUrl, favicon]) : undefined,
|
|
90
103
|
copyright: feedOptions.copyright,
|
|
91
104
|
});
|
|
92
105
|
|
|
@@ -131,121 +144,126 @@ export async function generateBlogPosts(
|
|
|
131
144
|
|
|
132
145
|
const blogPosts: BlogPost[] = [];
|
|
133
146
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
);
|
|
147
|
+
async function processBlogSourceFile(blogSourceFile: string) {
|
|
148
|
+
// Lookup in localized folder in priority
|
|
149
|
+
const blogDirPath = await getFolderContainingFile(
|
|
150
|
+
getContentPathList(contentPaths),
|
|
151
|
+
blogSourceFile,
|
|
152
|
+
);
|
|
141
153
|
|
|
142
|
-
|
|
154
|
+
const source = path.join(blogDirPath, blogSourceFile);
|
|
143
155
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
156
|
+
const {
|
|
157
|
+
frontMatter: unsafeFrontMatter,
|
|
158
|
+
content,
|
|
159
|
+
contentTitle,
|
|
160
|
+
excerpt,
|
|
161
|
+
} = await parseMarkdownFile(source, {removeContentTitle: true});
|
|
162
|
+
const frontMatter = validateBlogPostFrontMatter(unsafeFrontMatter);
|
|
163
|
+
|
|
164
|
+
const aliasedSource = aliasedSitePath(source, siteDir);
|
|
165
|
+
|
|
166
|
+
const blogFileName = path.basename(blogSourceFile);
|
|
167
|
+
|
|
168
|
+
if (frontMatter.draft && process.env.NODE_ENV === 'production') {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (frontMatter.id) {
|
|
173
|
+
console.warn(
|
|
174
|
+
chalk.yellow(
|
|
175
|
+
`"id" header option is deprecated in ${blogFileName} file. Please use "slug" option instead.`,
|
|
176
|
+
),
|
|
177
|
+
);
|
|
178
|
+
}
|
|
151
179
|
|
|
152
|
-
|
|
180
|
+
let date: Date | undefined;
|
|
181
|
+
// Extract date and title from filename.
|
|
182
|
+
const dateFilenameMatch = blogFileName.match(DATE_FILENAME_PATTERN);
|
|
183
|
+
let linkName = blogFileName.replace(/\.mdx?$/, '');
|
|
153
184
|
|
|
154
|
-
|
|
185
|
+
if (dateFilenameMatch) {
|
|
186
|
+
const [, dateString, name] = dateFilenameMatch;
|
|
187
|
+
// Always treat dates as UTC by adding the `Z`
|
|
188
|
+
date = new Date(`${dateString}Z`);
|
|
189
|
+
linkName = name;
|
|
190
|
+
}
|
|
155
191
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
192
|
+
// Prefer user-defined date.
|
|
193
|
+
if (frontMatter.date) {
|
|
194
|
+
date = frontMatter.date;
|
|
195
|
+
}
|
|
159
196
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
`${blogFileName} - 'id' header option is deprecated. Please use 'slug' option instead.`,
|
|
164
|
-
),
|
|
165
|
-
);
|
|
166
|
-
}
|
|
197
|
+
// Use file create time for blog.
|
|
198
|
+
date = date ?? (await fs.stat(source)).birthtime;
|
|
199
|
+
const formattedDate = formatBlogPostDate(i18n.currentLocale, date);
|
|
167
200
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
const dateFilenameMatch = blogFileName.match(DATE_FILENAME_PATTERN);
|
|
171
|
-
let linkName = blogFileName.replace(/\.mdx?$/, '');
|
|
201
|
+
const title = frontMatter.title ?? contentTitle ?? linkName;
|
|
202
|
+
const description = frontMatter.description ?? excerpt ?? '';
|
|
172
203
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
linkName = name;
|
|
177
|
-
}
|
|
204
|
+
const slug =
|
|
205
|
+
frontMatter.slug ||
|
|
206
|
+
(dateFilenameMatch ? toUrl({date, link: linkName}) : linkName);
|
|
178
207
|
|
|
179
|
-
|
|
180
|
-
if (frontMatter.date) {
|
|
181
|
-
date = frontMatter.date;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// Use file create time for blog.
|
|
185
|
-
date = date ?? (await fs.stat(source)).birthtime;
|
|
186
|
-
const formattedDate = new Intl.DateTimeFormat(i18n.currentLocale, {
|
|
187
|
-
day: 'numeric',
|
|
188
|
-
month: 'long',
|
|
189
|
-
year: 'numeric',
|
|
190
|
-
}).format(date);
|
|
208
|
+
const permalink = normalizeUrl([baseUrl, routeBasePath, slug]);
|
|
191
209
|
|
|
192
|
-
|
|
193
|
-
const
|
|
210
|
+
function getBlogEditUrl() {
|
|
211
|
+
const blogPathRelative = path.relative(blogDirPath, path.resolve(source));
|
|
194
212
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
213
|
+
if (typeof editUrl === 'function') {
|
|
214
|
+
return editUrl({
|
|
215
|
+
blogDirPath: posixPath(path.relative(siteDir, blogDirPath)),
|
|
216
|
+
blogPath: posixPath(blogPathRelative),
|
|
217
|
+
permalink,
|
|
218
|
+
locale: i18n.currentLocale,
|
|
219
|
+
});
|
|
220
|
+
} else if (typeof editUrl === 'string') {
|
|
221
|
+
const isLocalized = blogDirPath === contentPaths.contentPathLocalized;
|
|
222
|
+
const fileContentPath =
|
|
223
|
+
isLocalized && options.editLocalizedFiles
|
|
224
|
+
? contentPaths.contentPathLocalized
|
|
225
|
+
: contentPaths.contentPath;
|
|
226
|
+
|
|
227
|
+
const contentPathEditUrl = normalizeUrl([
|
|
228
|
+
editUrl,
|
|
229
|
+
posixPath(path.relative(siteDir, fileContentPath)),
|
|
230
|
+
]);
|
|
231
|
+
|
|
232
|
+
return getEditUrl(blogPathRelative, contentPathEditUrl);
|
|
233
|
+
} else {
|
|
234
|
+
return undefined;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
blogPosts.push({
|
|
239
|
+
id: frontMatter.slug ?? title,
|
|
240
|
+
metadata: {
|
|
241
|
+
permalink,
|
|
242
|
+
editUrl: getBlogEditUrl(),
|
|
243
|
+
source: aliasedSource,
|
|
244
|
+
title,
|
|
245
|
+
description,
|
|
246
|
+
date,
|
|
247
|
+
formattedDate,
|
|
248
|
+
tags: frontMatter.tags ?? [],
|
|
249
|
+
readingTime: showReadingTime ? readingTime(content).minutes : undefined,
|
|
250
|
+
truncated: truncateMarker?.test(content) || false,
|
|
251
|
+
},
|
|
252
|
+
});
|
|
253
|
+
}
|
|
200
254
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
255
|
+
await Promise.all(
|
|
256
|
+
blogSourceFiles.map(async (blogSourceFile: string) => {
|
|
257
|
+
try {
|
|
258
|
+
return await processBlogSourceFile(blogSourceFile);
|
|
259
|
+
} catch (e) {
|
|
260
|
+
console.error(
|
|
261
|
+
chalk.red(
|
|
262
|
+
`Processing of blog source file failed for path "${blogSourceFile}"`,
|
|
263
|
+
),
|
|
205
264
|
);
|
|
206
|
-
|
|
207
|
-
if (typeof editUrl === 'function') {
|
|
208
|
-
return editUrl({
|
|
209
|
-
blogDirPath: posixPath(path.relative(siteDir, blogDirPath)),
|
|
210
|
-
blogPath: posixPath(blogPathRelative),
|
|
211
|
-
permalink,
|
|
212
|
-
locale: i18n.currentLocale,
|
|
213
|
-
});
|
|
214
|
-
} else if (typeof editUrl === 'string') {
|
|
215
|
-
const isLocalized = blogDirPath === contentPaths.contentPathLocalized;
|
|
216
|
-
const fileContentPath =
|
|
217
|
-
isLocalized && options.editLocalizedFiles
|
|
218
|
-
? contentPaths.contentPathLocalized
|
|
219
|
-
: contentPaths.contentPath;
|
|
220
|
-
|
|
221
|
-
const contentPathEditUrl = normalizeUrl([
|
|
222
|
-
editUrl,
|
|
223
|
-
posixPath(path.relative(siteDir, fileContentPath)),
|
|
224
|
-
]);
|
|
225
|
-
|
|
226
|
-
return getEditUrl(blogPathRelative, contentPathEditUrl);
|
|
227
|
-
} else {
|
|
228
|
-
return undefined;
|
|
229
|
-
}
|
|
265
|
+
throw e;
|
|
230
266
|
}
|
|
231
|
-
|
|
232
|
-
blogPosts.push({
|
|
233
|
-
id: frontMatter.slug ?? title,
|
|
234
|
-
metadata: {
|
|
235
|
-
permalink,
|
|
236
|
-
editUrl: getBlogEditUrl(),
|
|
237
|
-
source: aliasedSource,
|
|
238
|
-
title,
|
|
239
|
-
description,
|
|
240
|
-
date,
|
|
241
|
-
formattedDate,
|
|
242
|
-
tags: frontMatter.tags ?? [],
|
|
243
|
-
readingTime: showReadingTime
|
|
244
|
-
? readingTime(content).minutes
|
|
245
|
-
: undefined,
|
|
246
|
-
truncated: truncateMarker?.test(content) || false,
|
|
247
|
-
},
|
|
248
|
-
});
|
|
249
267
|
}),
|
|
250
268
|
);
|
|
251
269
|
|