@docusaurus/plugin-content-blog 2.0.0-beta.6f366f4b4 → 2.0.0-beta.7

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.
Files changed (53) hide show
  1. package/lib/.tsbuildinfo +1 -1
  2. package/lib/authors.d.ts +23 -0
  3. package/lib/authors.js +150 -0
  4. package/lib/blogFrontMatter.d.ts +19 -6
  5. package/lib/blogFrontMatter.js +31 -19
  6. package/lib/blogUtils.d.ts +10 -2
  7. package/lib/blogUtils.js +146 -104
  8. package/lib/index.js +76 -70
  9. package/lib/markdownLoader.js +3 -3
  10. package/lib/pluginOptionSchema.d.ts +3 -27
  11. package/lib/pluginOptionSchema.js +19 -7
  12. package/lib/translations.d.ts +10 -0
  13. package/lib/translations.js +53 -0
  14. package/lib/types.d.ts +37 -14
  15. package/package.json +13 -11
  16. package/src/__tests__/__fixtures__/authorsMapFiles/authors.json +29 -0
  17. package/src/__tests__/__fixtures__/authorsMapFiles/authors.yml +27 -0
  18. package/src/__tests__/__fixtures__/authorsMapFiles/authorsBad1.json +5 -0
  19. package/src/__tests__/__fixtures__/authorsMapFiles/authorsBad1.yml +3 -0
  20. package/src/__tests__/__fixtures__/authorsMapFiles/authorsBad2.json +3 -0
  21. package/src/__tests__/__fixtures__/authorsMapFiles/authorsBad2.yml +2 -0
  22. package/src/__tests__/__fixtures__/authorsMapFiles/authorsBad3.json +8 -0
  23. package/src/__tests__/__fixtures__/authorsMapFiles/authorsBad3.yml +3 -0
  24. package/src/__tests__/__fixtures__/component/Typography.tsx +6 -0
  25. package/src/__tests__/__fixtures__/getAuthorsMapFilePath/contentPathEmpty/empty +0 -0
  26. package/src/__tests__/__fixtures__/getAuthorsMapFilePath/contentPathJson1/authors.json +0 -0
  27. package/src/__tests__/__fixtures__/getAuthorsMapFilePath/contentPathJson2/authors.json +0 -0
  28. package/src/__tests__/__fixtures__/getAuthorsMapFilePath/contentPathNestedYml/sub/folder/authors.yml +0 -0
  29. package/src/__tests__/__fixtures__/getAuthorsMapFilePath/contentPathYml1/authors.yml +0 -0
  30. package/src/__tests__/__fixtures__/getAuthorsMapFilePath/contentPathYml2/authors.yml +0 -0
  31. package/src/__tests__/__fixtures__/website/blog/2018-12-14-Happy-First-Birthday-Slash.md +3 -0
  32. package/src/__tests__/__fixtures__/website/blog/authors.yml +4 -0
  33. package/src/__tests__/__fixtures__/website/blog/mdx-blog-post.mdx +36 -0
  34. package/src/__tests__/__fixtures__/website/blog/simple-slug.md +4 -0
  35. package/src/__tests__/__fixtures__/website/i18n/en/docusaurus-plugin-content-blog/2018-12-14-Happy-First-Birthday-Slash.md +3 -0
  36. package/src/__tests__/__fixtures__/website/i18n/en/docusaurus-plugin-content-blog/authors.yml +5 -0
  37. package/src/__tests__/__snapshots__/generateBlogFeed.test.ts.snap +41 -3
  38. package/src/__tests__/__snapshots__/translations.test.ts.snap +64 -0
  39. package/src/__tests__/authors.test.ts +608 -0
  40. package/src/__tests__/blogFrontMatter.test.ts +93 -16
  41. package/src/__tests__/blogUtils.test.ts +94 -0
  42. package/src/__tests__/generateBlogFeed.test.ts +4 -0
  43. package/src/__tests__/index.test.ts +63 -12
  44. package/src/__tests__/pluginOptionSchema.test.ts +3 -3
  45. package/src/__tests__/translations.test.ts +92 -0
  46. package/src/authors.ts +202 -0
  47. package/src/blogFrontMatter.ts +73 -33
  48. package/src/blogUtils.ts +205 -132
  49. package/src/index.ts +92 -61
  50. package/{index.d.ts → src/plugin-content-blog.d.ts} +35 -31
  51. package/src/pluginOptionSchema.ts +22 -9
  52. package/src/translations.ts +63 -0
  53. package/src/types.ts +47 -16
@@ -11,6 +11,8 @@ import {
11
11
  } from '../blogFrontMatter';
12
12
  import escapeStringRegexp from 'escape-string-regexp';
13
13
 
14
+ // TODO this abstraction reduce verbosity but it makes it harder to debug
15
+ // It would be preferable to just expose helper methods
14
16
  function testField(params: {
15
17
  fieldName: keyof BlogPostFrontMatter;
16
18
  validFrontMatters: BlogPostFrontMatter[];
@@ -99,7 +101,30 @@ describe('validateBlogPostFrontMatter id', () => {
99
101
  testField({
100
102
  fieldName: 'id',
101
103
  validFrontMatters: [{id: '123'}, {id: 'id'}],
102
- invalidFrontMatters: [[{id: ''}, 'is not allowed to be empty']],
104
+ invalidFrontMatters: [[{id: ''}, 'not allowed to be empty']],
105
+ });
106
+ });
107
+
108
+ describe('validateBlogPostFrontMatter handles legacy/new author frontmatter', () => {
109
+ test('allow legacy author frontmatter', () => {
110
+ const frontMatter: BlogPostFrontMatter = {
111
+ author: 'Sebastien',
112
+ author_url: 'https://sebastienlorber.com',
113
+ author_title: 'maintainer',
114
+ author_image_url: 'https://github.com/slorber.png',
115
+ };
116
+ expect(validateBlogPostFrontMatter(frontMatter)).toEqual(frontMatter);
117
+ });
118
+
119
+ test('allow new authors frontmatter', () => {
120
+ const frontMatter: BlogPostFrontMatter = {
121
+ authors: [
122
+ 'slorber',
123
+ {name: 'Yangshun'},
124
+ {key: 'JMarcey', title: 'creator', random: '42'},
125
+ ],
126
+ };
127
+ expect(validateBlogPostFrontMatter(frontMatter)).toEqual(frontMatter);
103
128
  });
104
129
  });
105
130
 
@@ -107,21 +132,24 @@ describe('validateBlogPostFrontMatter author', () => {
107
132
  testField({
108
133
  fieldName: 'author',
109
134
  validFrontMatters: [{author: '123'}, {author: 'author'}],
110
- invalidFrontMatters: [[{author: ''}, 'is not allowed to be empty']],
135
+ invalidFrontMatters: [[{author: ''}, 'not allowed to be empty']],
111
136
  });
112
137
  });
113
138
 
114
139
  describe('validateBlogPostFrontMatter author_title', () => {
115
140
  testField({
116
141
  fieldName: 'author_title',
117
- validFrontMatters: [{author_title: '123'}, {author_title: 'author_title'}],
118
- invalidFrontMatters: [[{author_title: ''}, 'is not allowed to be empty']],
142
+ validFrontMatters: [
143
+ {author: '123', author_title: '123'},
144
+ {author: '123', author_title: 'author_title'},
145
+ ],
146
+ invalidFrontMatters: [[{author_title: ''}, 'not allowed to be empty']],
119
147
  });
120
148
 
121
149
  testField({
122
150
  fieldName: 'authorTitle',
123
151
  validFrontMatters: [{authorTitle: '123'}, {authorTitle: 'authorTitle'}],
124
- invalidFrontMatters: [[{authorTitle: ''}, 'is not allowed to be empty']],
152
+ invalidFrontMatters: [[{authorTitle: ''}, 'not allowed to be empty']],
125
153
  });
126
154
  });
127
155
 
@@ -136,7 +164,7 @@ describe('validateBlogPostFrontMatter author_url', () => {
136
164
  invalidFrontMatters: [
137
165
  [
138
166
  {author_url: ''},
139
- '"author_url" does not match any of the allowed types',
167
+ '"author_url" does not look like a valid url (value=\'\')',
140
168
  ],
141
169
  ],
142
170
  });
@@ -150,7 +178,10 @@ describe('validateBlogPostFrontMatter author_url', () => {
150
178
  ],
151
179
 
152
180
  invalidFrontMatters: [
153
- [{authorURL: ''}, '"authorURL" does not match any of the allowed types'],
181
+ [
182
+ {authorURL: ''},
183
+ '"authorURL" does not look like a valid url (value=\'\')',
184
+ ],
154
185
  ],
155
186
  });
156
187
  });
@@ -166,7 +197,7 @@ describe('validateBlogPostFrontMatter author_image_url', () => {
166
197
  invalidFrontMatters: [
167
198
  [
168
199
  {author_image_url: ''},
169
- '"author_image_url" does not match any of the allowed types',
200
+ '"author_image_url" does not look like a valid url (value=\'\')',
170
201
  ],
171
202
  ],
172
203
  });
@@ -181,7 +212,55 @@ describe('validateBlogPostFrontMatter author_image_url', () => {
181
212
  invalidFrontMatters: [
182
213
  [
183
214
  {authorImageURL: ''},
184
- '"authorImageURL" does not match any of the allowed types',
215
+ '"authorImageURL" does not look like a valid url (value=\'\')',
216
+ ],
217
+ ],
218
+ });
219
+ });
220
+
221
+ describe('validateBlogPostFrontMatter authors', () => {
222
+ testField({
223
+ fieldName: 'author',
224
+ validFrontMatters: [
225
+ {authors: []},
226
+ {authors: 'authorKey'},
227
+ {authors: ['authorKey1', 'authorKey2']},
228
+ {
229
+ authors: {
230
+ name: 'Author Name',
231
+ imageURL: '/absolute',
232
+ },
233
+ },
234
+ {
235
+ authors: {
236
+ key: 'authorKey',
237
+ title: 'Author title',
238
+ },
239
+ },
240
+ {
241
+ authors: [
242
+ 'authorKey1',
243
+ {key: 'authorKey3'},
244
+ 'authorKey3',
245
+ {name: 'Author Name 4'},
246
+ {key: 'authorKey5'},
247
+ ],
248
+ },
249
+ ],
250
+
251
+ invalidFrontMatters: [
252
+ [{authors: ''}, '"authors" is not allowed to be empty'],
253
+ [
254
+ {authors: [undefined]},
255
+ '"authors[0]" does not look like a valid blog post author. Please use an author key or an author object (with a key and/or name).',
256
+ ],
257
+ [
258
+ {authors: [null]},
259
+ '"authors[0]" does not look like a valid blog post author. Please use an author key or an author object (with a key and/or name).',
260
+ ],
261
+ [
262
+ {authors: [{}]},
263
+ '"authors[0]" does not look like a valid blog post author. Please use an author key or an author object (with a key and/or name).',
185
264
  ],
186
265
  ],
187
266
  });
@@ -200,7 +279,7 @@ describe('validateBlogPostFrontMatter slug', () => {
200
279
  {slug: '/api/plugins/@docusaurus/plugin-debug'},
201
280
  {slug: '@site/api/asset/image.png'},
202
281
  ],
203
- invalidFrontMatters: [[{slug: ''}, 'is not allowed to be empty']],
282
+ invalidFrontMatters: [[{slug: ''}, 'not allowed to be empty']],
204
283
  });
205
284
  });
206
285
 
@@ -219,7 +298,7 @@ describe('validateBlogPostFrontMatter image', () => {
219
298
  {image: '@site/api/asset/image.png'},
220
299
  ],
221
300
  invalidFrontMatters: [
222
- [{image: ''}, '"image" does not match any of the allowed types'],
301
+ [{image: ''}, '"image" does not look like a valid url (value=\'\')'],
223
302
  ],
224
303
  });
225
304
  });
@@ -235,8 +314,8 @@ describe('validateBlogPostFrontMatter tags', () => {
235
314
  {tags: ['hello', {label: 'tagLabel', permalink: '/tagPermalink'}]},
236
315
  ],
237
316
  invalidFrontMatters: [
238
- [{tags: ''}, 'must be an array'],
239
- [{tags: ['']}, 'is not allowed to be empty'],
317
+ [{tags: ''}, '"tags" does not look like a valid FrontMatter Yaml array.'],
318
+ [{tags: ['']}, 'not allowed to be empty'],
240
319
  ],
241
320
  // See https://github.com/facebook/docusaurus/issues/4642
242
321
  convertibleFrontMatter: [
@@ -260,7 +339,7 @@ describe('validateBlogPostFrontMatter keywords', () => {
260
339
  ],
261
340
  invalidFrontMatters: [
262
341
  [{keywords: ''}, 'must be an array'],
263
- [{keywords: ['']}, 'is not allowed to be empty'],
342
+ [{keywords: ['']}, 'not allowed to be empty'],
264
343
  [{keywords: []}, 'does not contain 1 required value(s)'],
265
344
  ],
266
345
  });
@@ -304,9 +383,7 @@ describe('validateBlogPostFrontMatter date', () => {
304
383
  fieldName: 'date',
305
384
  validFrontMatters: [
306
385
  {date: new Date('2020-01-01')},
307
- // @ts-expect-error: string for test
308
386
  {date: '2020-01-01'},
309
- // @ts-expect-error: string for test
310
387
  {date: '2020'},
311
388
  ],
312
389
  invalidFrontMatters: [
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ import {parseBlogFileName} from '../blogUtils';
9
+
10
+ describe('parseBlogFileName', () => {
11
+ test('parse file', () => {
12
+ expect(parseBlogFileName('some-post.md')).toEqual({
13
+ date: undefined,
14
+ text: 'some-post',
15
+ slug: '/some-post',
16
+ });
17
+ });
18
+
19
+ test('parse folder', () => {
20
+ expect(parseBlogFileName('some-post/index.md')).toEqual({
21
+ date: undefined,
22
+ text: 'some-post',
23
+ slug: '/some-post',
24
+ });
25
+ });
26
+
27
+ test('parse nested file', () => {
28
+ expect(parseBlogFileName('some-post/some-file.md')).toEqual({
29
+ date: undefined,
30
+ text: 'some-post/some-file',
31
+ slug: '/some-post/some-file',
32
+ });
33
+ });
34
+
35
+ test('parse nested folder', () => {
36
+ expect(parseBlogFileName('some-post/some-subfolder/index.md')).toEqual({
37
+ date: undefined,
38
+ text: 'some-post/some-subfolder',
39
+ slug: '/some-post/some-subfolder',
40
+ });
41
+ });
42
+
43
+ test('parse file respecting date convention', () => {
44
+ expect(
45
+ parseBlogFileName('2021-05-12-announcing-docusaurus-two-beta.md'),
46
+ ).toEqual({
47
+ date: new Date('2021-05-12Z'),
48
+ text: 'announcing-docusaurus-two-beta',
49
+ slug: '/2021/05/12/announcing-docusaurus-two-beta',
50
+ });
51
+ });
52
+
53
+ test('parse folder name respecting date convention', () => {
54
+ expect(
55
+ parseBlogFileName('2021-05-12-announcing-docusaurus-two-beta/index.md'),
56
+ ).toEqual({
57
+ date: new Date('2021-05-12Z'),
58
+ text: 'announcing-docusaurus-two-beta',
59
+ slug: '/2021/05/12/announcing-docusaurus-two-beta',
60
+ });
61
+ });
62
+
63
+ test('parse folder tree respecting date convention', () => {
64
+ expect(
65
+ parseBlogFileName('2021/05/12/announcing-docusaurus-two-beta/index.md'),
66
+ ).toEqual({
67
+ date: new Date('2021-05-12Z'),
68
+ text: 'announcing-docusaurus-two-beta',
69
+ slug: '/2021/05/12/announcing-docusaurus-two-beta',
70
+ });
71
+ });
72
+
73
+ test('parse folder name/tree (mixed) respecting date convention', () => {
74
+ expect(
75
+ parseBlogFileName('2021/05-12-announcing-docusaurus-two-beta/index.md'),
76
+ ).toEqual({
77
+ date: new Date('2021-05-12Z'),
78
+ text: 'announcing-docusaurus-two-beta',
79
+ slug: '/2021/05/12/announcing-docusaurus-two-beta',
80
+ });
81
+ });
82
+
83
+ test('parse nested folder tree respecting date convention', () => {
84
+ expect(
85
+ parseBlogFileName(
86
+ '2021/05/12/announcing-docusaurus-two-beta/subfolder/subfile.md',
87
+ ),
88
+ ).toEqual({
89
+ date: new Date('2021-05-12Z'),
90
+ text: 'announcing-docusaurus-two-beta/subfolder/subfile',
91
+ slug: '/2021/05/12/announcing-docusaurus-two-beta/subfolder/subfile',
92
+ });
93
+ });
94
+ });
@@ -52,6 +52,8 @@ describe('blogFeed', () => {
52
52
  {
53
53
  path: 'invalid-blog-path',
54
54
  routeBasePath: 'blog',
55
+ tagsBasePath: 'tags',
56
+ authorsMapPath: 'authors.yml',
55
57
  include: ['*.md', '*.mdx'],
56
58
  feedOptions: {
57
59
  type: [feedType],
@@ -85,6 +87,8 @@ describe('blogFeed', () => {
85
87
  {
86
88
  path: 'blog',
87
89
  routeBasePath: 'blog',
90
+ tagsBasePath: 'tags',
91
+ authorsMapPath: 'authors.yml',
88
92
  include: DEFAULT_OPTIONS.include,
89
93
  exclude: DEFAULT_OPTIONS.exclude,
90
94
  feedOptions: {
@@ -5,8 +5,6 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- /* eslint-disable @typescript-eslint/no-non-null-assertion */
9
-
10
8
  import fs from 'fs-extra';
11
9
  import path from 'path';
12
10
  import pluginContentBlog from '../index';
@@ -14,6 +12,7 @@ import {DocusaurusConfig, LoadContext, I18n} from '@docusaurus/types';
14
12
  import {PluginOptionSchema} from '../pluginOptionSchema';
15
13
  import {PluginOptions, EditUrlFunction, BlogPost} from '../types';
16
14
  import {Joi} from '@docusaurus/utils-validation';
15
+ import {posixPath} from '@docusaurus/utils';
17
16
 
18
17
  function findByTitle(
19
18
  blogPosts: BlogPost[],
@@ -60,7 +59,7 @@ describe('loadBlog', () => {
60
59
 
61
60
  const BaseEditUrl = 'https://baseEditUrl.com/edit';
62
61
 
63
- const getBlogPosts = async (
62
+ const getPlugin = async (
64
63
  siteDir: string,
65
64
  pluginOptions: Partial<PluginOptions> = {},
66
65
  i18n: I18n = DefaultI18N,
@@ -71,7 +70,7 @@ describe('loadBlog', () => {
71
70
  baseUrl: '/',
72
71
  url: 'https://docusaurus.io',
73
72
  } as DocusaurusConfig;
74
- const plugin = pluginContentBlog(
73
+ return pluginContentBlog(
75
74
  {
76
75
  siteDir,
77
76
  siteConfig,
@@ -84,11 +83,32 @@ describe('loadBlog', () => {
84
83
  ...pluginOptions,
85
84
  }),
86
85
  );
87
- const {blogPosts} = (await plugin.loadContent!())!;
86
+ };
88
87
 
88
+ const getBlogPosts = async (
89
+ siteDir: string,
90
+ pluginOptions: Partial<PluginOptions> = {},
91
+ i18n: I18n = DefaultI18N,
92
+ ) => {
93
+ const plugin = await getPlugin(siteDir, pluginOptions, i18n);
94
+ const {blogPosts} = (await plugin.loadContent!())!;
89
95
  return blogPosts;
90
96
  };
91
97
 
98
+ test('getPathsToWatch', async () => {
99
+ const siteDir = path.join(__dirname, '__fixtures__', 'website');
100
+ const plugin = await getPlugin(siteDir);
101
+ const pathsToWatch = plugin.getPathsToWatch!();
102
+ const relativePathsToWatch = pathsToWatch.map((p) =>
103
+ posixPath(path.relative(siteDir, p)),
104
+ );
105
+ expect(relativePathsToWatch).toEqual([
106
+ 'blog/authors.yml',
107
+ 'i18n/en/docusaurus-plugin-content-blog/**/*.{md,mdx}',
108
+ 'blog/**/*.{md,mdx}',
109
+ ]);
110
+ });
111
+
92
112
  test('simple website', async () => {
93
113
  const siteDir = path.join(__dirname, '__fixtures__', 'website');
94
114
  const blogPosts = await getBlogPosts(siteDir);
@@ -103,6 +123,7 @@ describe('loadBlog', () => {
103
123
  source: path.posix.join('@site', PluginPath, 'date-matter.md'),
104
124
  title: 'date-matter',
105
125
  description: `date inside front matter`,
126
+ authors: [],
106
127
  date: new Date('2019-01-01'),
107
128
  formattedDate: 'January 1, 2019',
108
129
  prevItem: undefined,
@@ -128,6 +149,16 @@ describe('loadBlog', () => {
128
149
  ),
129
150
  title: 'Happy 1st Birthday Slash! (translated)',
130
151
  description: `Happy birthday! (translated)`,
152
+ authors: [
153
+ {
154
+ name: 'Yangshun Tay (translated)',
155
+ },
156
+ {
157
+ key: 'slorber',
158
+ name: 'Sébastien Lorber (translated)',
159
+ title: 'Docusaurus maintainer (translated)',
160
+ },
161
+ ],
131
162
  date: new Date('2018-12-14'),
132
163
  formattedDate: 'December 14, 2018',
133
164
  tags: [],
@@ -148,6 +179,7 @@ describe('loadBlog', () => {
148
179
  source: path.posix.join('@site', PluginPath, 'complex-slug.md'),
149
180
  title: 'Complex Slug',
150
181
  description: `complex url slug`,
182
+ authors: [],
151
183
  prevItem: undefined,
152
184
  nextItem: {
153
185
  permalink: '/blog/simple/slug',
@@ -169,6 +201,14 @@ describe('loadBlog', () => {
169
201
  source: path.posix.join('@site', PluginPath, 'simple-slug.md'),
170
202
  title: 'Simple Slug',
171
203
  description: `simple url slug`,
204
+ authors: [
205
+ {
206
+ name: 'Sébastien Lorber',
207
+ title: 'Docusaurus maintainer',
208
+ url: 'https://sebastienlorber.com',
209
+ imageURL: undefined,
210
+ },
211
+ ],
172
212
  prevItem: undefined,
173
213
  nextItem: {
174
214
  permalink: '/blog/draft',
@@ -190,6 +230,7 @@ describe('loadBlog', () => {
190
230
  source: path.posix.join('@site', PluginPath, 'heading-as-title.md'),
191
231
  title: 'some heading',
192
232
  description: '',
233
+ authors: [],
193
234
  date: new Date('2019-01-02'),
194
235
  formattedDate: 'January 2, 2019',
195
236
  prevItem: undefined,
@@ -205,23 +246,26 @@ describe('loadBlog', () => {
205
246
  test('simple website blog dates localized', async () => {
206
247
  const siteDir = path.join(__dirname, '__fixtures__', 'website');
207
248
  const blogPostsFrench = await getBlogPosts(siteDir, {}, getI18n('fr'));
208
- expect(blogPostsFrench).toHaveLength(6);
249
+ expect(blogPostsFrench).toHaveLength(7);
209
250
  expect(blogPostsFrench[0].metadata.formattedDate).toMatchInlineSnapshot(
210
- `"16 août 2020"`,
251
+ `"5 mars 2021"`,
211
252
  );
212
253
  expect(blogPostsFrench[1].metadata.formattedDate).toMatchInlineSnapshot(
213
- `"15 août 2020"`,
254
+ `"16 août 2020"`,
214
255
  );
215
256
  expect(blogPostsFrench[2].metadata.formattedDate).toMatchInlineSnapshot(
216
- `"27 février 2020"`,
257
+ `"15 août 2020"`,
217
258
  );
218
259
  expect(blogPostsFrench[3].metadata.formattedDate).toMatchInlineSnapshot(
219
- `"2 janvier 2019"`,
260
+ `"27 février 2020"`,
220
261
  );
221
262
  expect(blogPostsFrench[4].metadata.formattedDate).toMatchInlineSnapshot(
222
- `"1 janvier 2019"`,
263
+ `"2 janvier 2019"`,
223
264
  );
224
265
  expect(blogPostsFrench[5].metadata.formattedDate).toMatchInlineSnapshot(
266
+ `"1 janvier 2019"`,
267
+ );
268
+ expect(blogPostsFrench[6].metadata.formattedDate).toMatchInlineSnapshot(
225
269
  `"14 décembre 2018"`,
226
270
  );
227
271
  });
@@ -251,7 +295,7 @@ describe('loadBlog', () => {
251
295
  expect(blogPost.metadata.editUrl).toEqual(hardcodedEditUrl);
252
296
  });
253
297
 
254
- expect(editUrlFunction).toHaveBeenCalledTimes(6);
298
+ expect(editUrlFunction).toHaveBeenCalledTimes(7);
255
299
  expect(editUrlFunction).toHaveBeenCalledWith({
256
300
  blogDirPath: 'blog',
257
301
  blogPath: 'date-matter.md',
@@ -264,6 +308,12 @@ describe('loadBlog', () => {
264
308
  permalink: '/blog/draft',
265
309
  locale: 'en',
266
310
  });
311
+ expect(editUrlFunction).toHaveBeenCalledWith({
312
+ blogDirPath: 'blog',
313
+ blogPath: 'mdx-blog-post.mdx',
314
+ permalink: '/blog/mdx-blog-post',
315
+ locale: 'en',
316
+ });
267
317
  expect(editUrlFunction).toHaveBeenCalledWith({
268
318
  blogDirPath: 'blog',
269
319
  blogPath: 'complex-slug.md',
@@ -325,6 +375,7 @@ describe('loadBlog', () => {
325
375
  source: noDateSource,
326
376
  title: 'no date',
327
377
  description: `no date`,
378
+ authors: [],
328
379
  date: noDateSourceBirthTime,
329
380
  formattedDate,
330
381
  tags: [],
@@ -29,7 +29,7 @@ test('should accept correctly defined user options', () => {
29
29
  const {value, error} = PluginOptionSchema.validate(userOptions);
30
30
  expect(value).toEqual({
31
31
  ...userOptions,
32
- feedOptions: {type: ['rss'], title: 'myTitle'},
32
+ feedOptions: {type: ['rss'], title: 'myTitle', copyright: ''},
33
33
  });
34
34
  expect(error).toBe(undefined);
35
35
  });
@@ -78,7 +78,7 @@ test('should convert all feed type to array with other feed type', () => {
78
78
  });
79
79
  expect(value).toEqual({
80
80
  ...DEFAULT_OPTIONS,
81
- feedOptions: {type: ['rss', 'atom']},
81
+ feedOptions: {type: ['rss', 'atom'], copyright: ''},
82
82
  });
83
83
  });
84
84
 
@@ -106,7 +106,7 @@ test('should have array with rss + atom, title for missing feed type', () => {
106
106
  });
107
107
  expect(value).toEqual({
108
108
  ...DEFAULT_OPTIONS,
109
- feedOptions: {type: ['rss', 'atom'], title: 'title'},
109
+ feedOptions: {type: ['rss', 'atom'], title: 'title', copyright: ''},
110
110
  });
111
111
  });
112
112
 
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ import {BlogPost, BlogContent, PluginOptions} from '../types';
9
+ import {getTranslationFiles, translateContent} from '../translations';
10
+ import {DEFAULT_OPTIONS} from '../pluginOptionSchema';
11
+ import {updateTranslationFileMessages} from '@docusaurus/utils';
12
+
13
+ const sampleBlogOptions: PluginOptions = {
14
+ ...DEFAULT_OPTIONS,
15
+ blogSidebarTitle: 'All my posts',
16
+ blogTitle: 'My blog',
17
+ blogDescription: "Someone's random blog",
18
+ };
19
+
20
+ const sampleBlogPosts: BlogPost[] = [
21
+ {
22
+ id: 'hello',
23
+ metadata: {
24
+ permalink: '/blog/2021/06/19/hello',
25
+ source: '/blog/2021/06/19/hello',
26
+ description: '/blog/2021/06/19/hello',
27
+ date: new Date(2021, 6, 19),
28
+ formattedDate: 'June 19, 2021',
29
+ tags: [],
30
+ title: 'Hello',
31
+ truncated: true,
32
+ },
33
+ },
34
+ ];
35
+
36
+ const sampleBlogContent: BlogContent = {
37
+ blogSidebarTitle: sampleBlogOptions.blogSidebarTitle,
38
+ blogListPaginated: [
39
+ {
40
+ items: ['hello'],
41
+ metadata: {
42
+ permalink: '/',
43
+ page: 1,
44
+ postsPerPage: 10,
45
+ totalPages: 1,
46
+ totalCount: 1,
47
+ previousPage: null,
48
+ nextPage: null,
49
+ blogTitle: sampleBlogOptions.blogTitle,
50
+ blogDescription: sampleBlogOptions.blogDescription,
51
+ },
52
+ },
53
+ ],
54
+ blogPosts: sampleBlogPosts,
55
+ blogTags: {},
56
+ blogTagsListPath: '/tags',
57
+ };
58
+
59
+ function getSampleTranslationFiles() {
60
+ return getTranslationFiles(sampleBlogOptions);
61
+ }
62
+ function getSampleTranslationFilesTranslated() {
63
+ const translationFiles = getSampleTranslationFiles();
64
+ return translationFiles.map((translationFile) =>
65
+ updateTranslationFileMessages(
66
+ translationFile,
67
+ (message) => `${message} (translated)`,
68
+ ),
69
+ );
70
+ }
71
+
72
+ describe('getContentTranslationFiles', () => {
73
+ test('should return translation files matching snapshot', async () => {
74
+ expect(getSampleTranslationFiles()).toMatchSnapshot();
75
+ });
76
+ });
77
+
78
+ describe('translateContent', () => {
79
+ test('should not translate anything if translation files are untranslated', () => {
80
+ const translationFiles = getSampleTranslationFiles();
81
+ expect(translateContent(sampleBlogContent, translationFiles)).toEqual(
82
+ sampleBlogContent,
83
+ );
84
+ });
85
+
86
+ test('should return translated loaded content matching snapshot', () => {
87
+ const translationFiles = getSampleTranslationFilesTranslated();
88
+ expect(
89
+ translateContent(sampleBlogContent, translationFiles),
90
+ ).toMatchSnapshot();
91
+ });
92
+ });