@docusaurus/plugin-content-blog 2.0.0-beta.fbdeefcac → 2.0.0-rc.1

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 (57) hide show
  1. package/lib/authors.d.ts +22 -0
  2. package/lib/authors.js +122 -0
  3. package/lib/blogUtils.d.ts +27 -7
  4. package/lib/blogUtils.js +201 -145
  5. package/lib/feed.d.ts +15 -0
  6. package/lib/feed.js +102 -0
  7. package/lib/frontMatter.d.ts +10 -0
  8. package/lib/{blogFrontMatter.js → frontMatter.js} +31 -19
  9. package/lib/index.d.ts +4 -4
  10. package/lib/index.js +165 -201
  11. package/lib/markdownLoader.d.ts +3 -6
  12. package/lib/markdownLoader.js +6 -7
  13. package/lib/options.d.ts +10 -0
  14. package/lib/{pluginOptionSchema.js → options.js} +44 -14
  15. package/lib/remark/footnoteIDFixer.d.ts +14 -0
  16. package/lib/remark/footnoteIDFixer.js +29 -0
  17. package/lib/translations.d.ts +10 -0
  18. package/lib/translations.js +53 -0
  19. package/lib/types.d.ts +4 -109
  20. package/package.json +23 -19
  21. package/src/authors.ts +168 -0
  22. package/src/blogUtils.ts +306 -204
  23. package/src/feed.ts +171 -0
  24. package/src/frontMatter.ts +81 -0
  25. package/src/index.ts +230 -269
  26. package/src/markdownLoader.ts +11 -16
  27. package/src/{pluginOptionSchema.ts → options.ts} +57 -16
  28. package/src/plugin-content-blog.d.ts +587 -0
  29. package/src/remark/footnoteIDFixer.ts +29 -0
  30. package/src/translations.ts +69 -0
  31. package/src/types.ts +2 -128
  32. package/index.d.ts +0 -138
  33. package/lib/.tsbuildinfo +0 -1
  34. package/lib/blogFrontMatter.d.ts +0 -28
  35. package/lib/pluginOptionSchema.d.ts +0 -33
  36. package/src/__tests__/__fixtures__/website/blog/2018-12-14-Happy-First-Birthday-Slash.md +0 -5
  37. package/src/__tests__/__fixtures__/website/blog/complex-slug.md +0 -7
  38. package/src/__tests__/__fixtures__/website/blog/date-matter.md +0 -5
  39. package/src/__tests__/__fixtures__/website/blog/draft.md +0 -6
  40. package/src/__tests__/__fixtures__/website/blog/heading-as-title.md +0 -5
  41. package/src/__tests__/__fixtures__/website/blog/simple-slug.md +0 -7
  42. package/src/__tests__/__fixtures__/website/blog-with-ref/2018-12-14-Happy-First-Birthday-Slash.md +0 -5
  43. package/src/__tests__/__fixtures__/website/blog-with-ref/post-with-broken-links.md +0 -11
  44. package/src/__tests__/__fixtures__/website/blog-with-ref/post.md +0 -5
  45. package/src/__tests__/__fixtures__/website/i18n/en/docusaurus-plugin-content-blog/2018-12-14-Happy-First-Birthday-Slash.md +0 -5
  46. package/src/__tests__/__fixtures__/website-blog-without-date/blog/no date.md +0 -1
  47. package/src/__tests__/__snapshots__/generateBlogFeed.test.ts.snap +0 -76
  48. package/src/__tests__/__snapshots__/linkify.test.ts.snap +0 -24
  49. package/src/__tests__/__snapshots__/pluginOptionSchema.test.ts.snap +0 -5
  50. package/src/__tests__/blogFrontMatter.test.ts +0 -317
  51. package/src/__tests__/generateBlogFeed.test.ts +0 -100
  52. package/src/__tests__/index.test.ts +0 -336
  53. package/src/__tests__/linkify.test.ts +0 -93
  54. package/src/__tests__/pluginOptionSchema.test.ts +0 -150
  55. package/src/blogFrontMatter.ts +0 -88
  56. package/tsconfig.json +0 -9
  57. package/types.d.ts +0 -13
package/lib/feed.js ADDED
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) Facebook, Inc. and its affiliates.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.createBlogFeedFiles = void 0;
10
+ const tslib_1 = require("tslib");
11
+ const path_1 = tslib_1.__importDefault(require("path"));
12
+ const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
13
+ const logger_1 = tslib_1.__importDefault(require("@docusaurus/logger"));
14
+ const feed_1 = require("feed");
15
+ const utils_1 = require("@docusaurus/utils");
16
+ const utils_common_1 = require("@docusaurus/utils-common");
17
+ const cheerio_1 = require("cheerio");
18
+ async function generateBlogFeed({ blogPosts, options, siteConfig, outDir, locale, }) {
19
+ if (!blogPosts.length) {
20
+ return null;
21
+ }
22
+ const { feedOptions, routeBasePath } = options;
23
+ const { url: siteUrl, baseUrl, title, favicon } = siteConfig;
24
+ const blogBaseUrl = (0, utils_1.normalizeUrl)([siteUrl, baseUrl, routeBasePath]);
25
+ const updated = blogPosts[0]?.metadata.date;
26
+ const feed = new feed_1.Feed({
27
+ id: blogBaseUrl,
28
+ title: feedOptions.title ?? `${title} Blog`,
29
+ updated,
30
+ language: feedOptions.language ?? locale,
31
+ link: blogBaseUrl,
32
+ description: feedOptions.description ?? `${siteConfig.title} Blog`,
33
+ favicon: favicon ? (0, utils_1.normalizeUrl)([siteUrl, baseUrl, favicon]) : undefined,
34
+ copyright: feedOptions.copyright,
35
+ });
36
+ function toFeedAuthor(author) {
37
+ return { name: author.name, link: author.url, email: author.email };
38
+ }
39
+ await Promise.all(blogPosts.map(async (post) => {
40
+ const { id, metadata: { title: metadataTitle, permalink, date, description, authors, tags, }, } = post;
41
+ const content = await (0, utils_1.readOutputHTMLFile)(permalink.replace(siteConfig.baseUrl, ''), outDir, siteConfig.trailingSlash);
42
+ const $ = (0, cheerio_1.load)(content);
43
+ const feedItem = {
44
+ title: metadataTitle,
45
+ id,
46
+ link: (0, utils_1.normalizeUrl)([siteUrl, permalink]),
47
+ date,
48
+ description,
49
+ // Atom feed demands the "term", while other feeds use "name"
50
+ category: tags.map((tag) => ({ name: tag.label, term: tag.label })),
51
+ content: $(`#${utils_common_1.blogPostContainerID}`).html(),
52
+ };
53
+ // json1() method takes the first item of authors array
54
+ // it causes an error when authors array is empty
55
+ const feedItemAuthors = authors.map(toFeedAuthor);
56
+ if (feedItemAuthors.length > 0) {
57
+ feedItem.author = feedItemAuthors;
58
+ }
59
+ return feedItem;
60
+ })).then((items) => items.forEach(feed.addItem));
61
+ return feed;
62
+ }
63
+ async function createBlogFeedFile({ feed, feedType, generatePath, }) {
64
+ const [feedContent, feedPath] = (() => {
65
+ switch (feedType) {
66
+ case 'rss':
67
+ return [feed.rss2(), 'rss.xml'];
68
+ case 'json':
69
+ return [feed.json1(), 'feed.json'];
70
+ case 'atom':
71
+ return [feed.atom1(), 'atom.xml'];
72
+ default:
73
+ throw new Error(`Feed type ${feedType} not supported.`);
74
+ }
75
+ })();
76
+ try {
77
+ await fs_extra_1.default.outputFile(path_1.default.join(generatePath, feedPath), feedContent);
78
+ }
79
+ catch (err) {
80
+ logger_1.default.error(`Generating ${feedType} feed failed.`);
81
+ throw err;
82
+ }
83
+ }
84
+ async function createBlogFeedFiles({ blogPosts, options, siteConfig, outDir, locale, }) {
85
+ const feed = await generateBlogFeed({
86
+ blogPosts,
87
+ options,
88
+ siteConfig,
89
+ outDir,
90
+ locale,
91
+ });
92
+ const feedTypes = options.feedOptions.type;
93
+ if (!feed || !feedTypes) {
94
+ return;
95
+ }
96
+ await Promise.all(feedTypes.map((feedType) => createBlogFeedFile({
97
+ feed,
98
+ feedType,
99
+ generatePath: path_1.default.join(outDir, options.routeBasePath),
100
+ })));
101
+ }
102
+ exports.createBlogFeedFiles = createBlogFeedFiles;
@@ -0,0 +1,10 @@
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
+ import type { BlogPostFrontMatter } from '@docusaurus/plugin-content-blog';
8
+ export declare function validateBlogPostFrontMatter(frontMatter: {
9
+ [key: string]: unknown;
10
+ }): BlogPostFrontMatter;
@@ -7,44 +7,56 @@
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.validateBlogPostFrontMatter = void 0;
10
- /* eslint-disable camelcase */
11
10
  const utils_validation_1 = require("@docusaurus/utils-validation");
12
- // NOTE: we don't add any default value on purpose here
13
- // We don't want default values to magically appear in doc metadatas and props
14
- // While the user did not provide those values explicitly
15
- // We use default values in code instead
16
- const BlogTagSchema = utils_validation_1.JoiFrontMatter.alternatives().try(utils_validation_1.JoiFrontMatter.string().required(), utils_validation_1.JoiFrontMatter.object({
17
- label: utils_validation_1.JoiFrontMatter.string().required(),
18
- permalink: utils_validation_1.JoiFrontMatter.string().required(),
19
- }));
11
+ const BlogPostFrontMatterAuthorSchema = utils_validation_1.JoiFrontMatter.object({
12
+ key: utils_validation_1.JoiFrontMatter.string(),
13
+ name: utils_validation_1.JoiFrontMatter.string(),
14
+ title: utils_validation_1.JoiFrontMatter.string(),
15
+ url: utils_validation_1.URISchema,
16
+ imageURL: utils_validation_1.JoiFrontMatter.string(),
17
+ })
18
+ .or('key', 'name', 'imageURL')
19
+ .rename('image_url', 'imageURL', { alias: true });
20
+ const FrontMatterAuthorErrorMessage = '{{#label}} does not look like a valid blog post author. Please use an author key or an author object (with a key and/or name).';
20
21
  const BlogFrontMatterSchema = utils_validation_1.JoiFrontMatter.object({
21
22
  id: utils_validation_1.JoiFrontMatter.string(),
22
23
  title: utils_validation_1.JoiFrontMatter.string().allow(''),
23
24
  description: utils_validation_1.JoiFrontMatter.string().allow(''),
24
- tags: utils_validation_1.JoiFrontMatter.array().items(BlogTagSchema),
25
+ tags: utils_validation_1.FrontMatterTagsSchema,
25
26
  draft: utils_validation_1.JoiFrontMatter.boolean(),
26
27
  date: utils_validation_1.JoiFrontMatter.date().raw(),
28
+ // New multi-authors front matter:
29
+ authors: utils_validation_1.JoiFrontMatter.alternatives()
30
+ .try(utils_validation_1.JoiFrontMatter.string(), BlogPostFrontMatterAuthorSchema, utils_validation_1.JoiFrontMatter.array()
31
+ .items(utils_validation_1.JoiFrontMatter.string(), BlogPostFrontMatterAuthorSchema)
32
+ .messages({
33
+ 'array.sparse': FrontMatterAuthorErrorMessage,
34
+ 'array.includes': FrontMatterAuthorErrorMessage,
35
+ }))
36
+ .messages({
37
+ 'alternatives.match': FrontMatterAuthorErrorMessage,
38
+ }),
39
+ // Legacy author front matter
27
40
  author: utils_validation_1.JoiFrontMatter.string(),
28
41
  author_title: utils_validation_1.JoiFrontMatter.string(),
29
42
  author_url: utils_validation_1.URISchema,
30
43
  author_image_url: utils_validation_1.URISchema,
31
- slug: utils_validation_1.JoiFrontMatter.string(),
32
- image: utils_validation_1.URISchema,
33
- keywords: utils_validation_1.JoiFrontMatter.array().items(utils_validation_1.JoiFrontMatter.string().required()),
34
- hide_table_of_contents: utils_validation_1.JoiFrontMatter.boolean(),
35
- // TODO re-enable warnings later, our v1 blog posts use those older frontmatter fields
44
+ // TODO enable deprecation warnings later
36
45
  authorURL: utils_validation_1.URISchema,
37
46
  // .warning('deprecate.error', { alternative: '"author_url"'}),
38
47
  authorTitle: utils_validation_1.JoiFrontMatter.string(),
39
48
  // .warning('deprecate.error', { alternative: '"author_title"'}),
40
49
  authorImageURL: utils_validation_1.URISchema,
41
50
  // .warning('deprecate.error', { alternative: '"author_image_url"'}),
42
- })
43
- .unknown()
44
- .messages({
51
+ slug: utils_validation_1.JoiFrontMatter.string(),
52
+ image: utils_validation_1.URISchema,
53
+ keywords: utils_validation_1.JoiFrontMatter.array().items(utils_validation_1.JoiFrontMatter.string().required()),
54
+ hide_table_of_contents: utils_validation_1.JoiFrontMatter.boolean(),
55
+ ...utils_validation_1.FrontMatterTOCHeadingLevels,
56
+ }).messages({
45
57
  'deprecate.error': '{#label} blog frontMatter field is deprecated. Please use {#alternative} instead.',
46
58
  });
47
59
  function validateBlogPostFrontMatter(frontMatter) {
48
- return utils_validation_1.validateFrontMatter(frontMatter, BlogFrontMatterSchema);
60
+ return (0, utils_validation_1.validateFrontMatter)(frontMatter, BlogFrontMatterSchema);
49
61
  }
50
62
  exports.validateBlogPostFrontMatter = validateBlogPostFrontMatter;
package/lib/index.d.ts CHANGED
@@ -4,7 +4,7 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
- import { PluginOptions, BlogContent } from './types';
8
- import { LoadContext, Plugin, OptionValidationContext, ValidationResult } from '@docusaurus/types';
9
- export default function pluginContentBlog(context: LoadContext, options: PluginOptions): Plugin<BlogContent>;
10
- export declare function validateOptions({ validate, options, }: OptionValidationContext<PluginOptions>): ValidationResult<PluginOptions>;
7
+ import type { LoadContext, Plugin } from '@docusaurus/types';
8
+ import type { PluginOptions, BlogContent } from '@docusaurus/plugin-content-blog';
9
+ export default function pluginContentBlog(context: LoadContext, options: PluginOptions): Promise<Plugin<BlogContent>>;
10
+ export { validateOptions } from './options';