@docusaurus/plugin-content-blog 2.0.0-beta.677e53d4d → 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 (56) 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 +78 -77
  9. package/lib/markdownLoader.js +3 -3
  10. package/lib/pluginOptionSchema.d.ts +3 -26
  11. package/lib/pluginOptionSchema.js +22 -7
  12. package/lib/translations.d.ts +10 -0
  13. package/lib/translations.js +53 -0
  14. package/lib/types.d.ts +38 -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/_partials/somePartial.md +3 -0
  33. package/src/__tests__/__fixtures__/website/blog/_partials/subfolder/somePartial.md +3 -0
  34. package/src/__tests__/__fixtures__/website/blog/_somePartial.md +3 -0
  35. package/src/__tests__/__fixtures__/website/blog/authors.yml +4 -0
  36. package/src/__tests__/__fixtures__/website/blog/mdx-blog-post.mdx +36 -0
  37. package/src/__tests__/__fixtures__/website/blog/simple-slug.md +4 -0
  38. package/src/__tests__/__fixtures__/website/i18n/en/docusaurus-plugin-content-blog/2018-12-14-Happy-First-Birthday-Slash.md +3 -0
  39. package/src/__tests__/__fixtures__/website/i18n/en/docusaurus-plugin-content-blog/authors.yml +5 -0
  40. package/src/__tests__/__snapshots__/generateBlogFeed.test.ts.snap +81 -3
  41. package/src/__tests__/__snapshots__/translations.test.ts.snap +64 -0
  42. package/src/__tests__/authors.test.ts +608 -0
  43. package/src/__tests__/blogFrontMatter.test.ts +93 -16
  44. package/src/__tests__/blogUtils.test.ts +94 -0
  45. package/src/__tests__/generateBlogFeed.test.ts +7 -1
  46. package/src/__tests__/index.test.ts +63 -12
  47. package/src/__tests__/pluginOptionSchema.test.ts +3 -3
  48. package/src/__tests__/translations.test.ts +92 -0
  49. package/src/authors.ts +202 -0
  50. package/src/blogFrontMatter.ts +73 -33
  51. package/src/blogUtils.ts +206 -131
  52. package/src/index.ts +98 -71
  53. package/{index.d.ts → src/plugin-content-blog.d.ts} +35 -31
  54. package/src/pluginOptionSchema.ts +25 -9
  55. package/src/translations.ts +63 -0
  56. package/src/types.ts +48 -16
@@ -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')
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 frontmatter:
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 frontmatter
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;
@@ -5,15 +5,23 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  import { Feed } from 'feed';
8
- import { PluginOptions, BlogPost, BlogContentPaths, BlogMarkdownLoaderOptions } from './types';
8
+ import { PluginOptions, BlogPost, BlogContentPaths, BlogMarkdownLoaderOptions, BlogTags } from './types';
9
9
  import { LoadContext } from '@docusaurus/types';
10
10
  export declare function truncate(fileString: string, truncateMarker: RegExp): string;
11
11
  export declare function getSourceToPermalink(blogPosts: BlogPost[]): Record<string, string>;
12
+ export declare function getBlogTags(blogPosts: BlogPost[]): BlogTags;
13
+ declare type ParsedBlogFileName = {
14
+ date: Date | undefined;
15
+ text: string;
16
+ slug: string;
17
+ };
18
+ export declare function parseBlogFileName(blogSourceRelative: string): ParsedBlogFileName;
12
19
  export declare function generateBlogFeed(contentPaths: BlogContentPaths, context: LoadContext, options: PluginOptions): Promise<Feed | null>;
13
- export declare function generateBlogPosts(contentPaths: BlogContentPaths, { siteConfig, siteDir, i18n }: LoadContext, options: PluginOptions): Promise<BlogPost[]>;
20
+ export declare function generateBlogPosts(contentPaths: BlogContentPaths, context: LoadContext, options: PluginOptions): Promise<BlogPost[]>;
14
21
  export declare type LinkifyParams = {
15
22
  filePath: string;
16
23
  fileString: string;
17
24
  } & Pick<BlogMarkdownLoaderOptions, 'sourceToPermalink' | 'siteDir' | 'contentPaths' | 'onBrokenMarkdownLink'>;
18
25
  export declare function linkify({ filePath, contentPaths, fileString, siteDir, sourceToPermalink, onBrokenMarkdownLink, }: LinkifyParams): string;
19
26
  export declare function getContentPathList(contentPaths: BlogContentPaths): string[];
27
+ export {};
package/lib/blogUtils.js CHANGED
@@ -6,34 +6,55 @@
6
6
  * LICENSE file in the root directory of this source tree.
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.getContentPathList = exports.linkify = exports.generateBlogPosts = exports.generateBlogFeed = exports.getSourceToPermalink = exports.truncate = void 0;
9
+ exports.getContentPathList = exports.linkify = exports.generateBlogPosts = exports.generateBlogFeed = exports.parseBlogFileName = exports.getBlogTags = exports.getSourceToPermalink = exports.truncate = void 0;
10
10
  const tslib_1 = require("tslib");
11
- const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
12
- const globby_1 = tslib_1.__importDefault(require("globby"));
13
- const chalk_1 = tslib_1.__importDefault(require("chalk"));
14
- const path_1 = tslib_1.__importDefault(require("path"));
15
- const reading_time_1 = tslib_1.__importDefault(require("reading-time"));
11
+ const fs_extra_1 = (0, tslib_1.__importDefault)(require("fs-extra"));
12
+ const chalk_1 = (0, tslib_1.__importDefault)(require("chalk"));
13
+ const path_1 = (0, tslib_1.__importDefault)(require("path"));
14
+ const reading_time_1 = (0, tslib_1.__importDefault)(require("reading-time"));
16
15
  const feed_1 = require("feed");
17
16
  const lodash_1 = require("lodash");
18
17
  const utils_1 = require("@docusaurus/utils");
19
18
  const blogFrontMatter_1 = require("./blogFrontMatter");
19
+ const authors_1 = require("./authors");
20
20
  function truncate(fileString, truncateMarker) {
21
21
  return fileString.split(truncateMarker, 1).shift();
22
22
  }
23
23
  exports.truncate = truncate;
24
24
  function getSourceToPermalink(blogPosts) {
25
- return lodash_1.mapValues(lodash_1.keyBy(blogPosts, (item) => item.metadata.source), (v) => v.metadata.permalink);
25
+ return (0, lodash_1.mapValues)((0, lodash_1.keyBy)(blogPosts, (item) => item.metadata.source), (v) => v.metadata.permalink);
26
26
  }
27
27
  exports.getSourceToPermalink = getSourceToPermalink;
28
- // YYYY-MM-DD-{name}.mdx?
29
- // Prefer named capture, but older Node versions do not support it.
30
- const DATE_FILENAME_PATTERN = /^(\d{4}-\d{1,2}-\d{1,2})-?(.*?).mdx?$/;
31
- function toUrl({ date, link }) {
32
- return `${date
33
- .toISOString()
34
- .substring(0, '2019-01-01'.length)
35
- .replace(/-/g, '/')}/${link}`;
28
+ function getBlogTags(blogPosts) {
29
+ const groups = (0, utils_1.groupTaggedItems)(blogPosts, (blogPost) => blogPost.metadata.tags);
30
+ return (0, lodash_1.mapValues)(groups, (group) => {
31
+ return {
32
+ name: group.tag.label,
33
+ items: group.items.map((item) => item.id),
34
+ permalink: group.tag.permalink,
35
+ };
36
+ });
37
+ }
38
+ exports.getBlogTags = getBlogTags;
39
+ const DATE_FILENAME_REGEX = /^(?<date>\d{4}[-/]\d{1,2}[-/]\d{1,2})[-/]?(?<text>.*?)(\/index)?.mdx?$/;
40
+ function parseBlogFileName(blogSourceRelative) {
41
+ const dateFilenameMatch = blogSourceRelative.match(DATE_FILENAME_REGEX);
42
+ if (dateFilenameMatch) {
43
+ const dateString = dateFilenameMatch.groups.date;
44
+ const text = dateFilenameMatch.groups.text;
45
+ // Always treat dates as UTC by adding the `Z`
46
+ const date = new Date(`${dateString}Z`);
47
+ const slugDate = dateString.replace(/-/g, '/');
48
+ const slug = `/${slugDate}/${text}`;
49
+ return { date, text, slug };
50
+ }
51
+ else {
52
+ const text = blogSourceRelative.replace(/(\/index)?\.mdx?$/, '');
53
+ const slug = `/${text}`;
54
+ return { date: undefined, text, slug };
55
+ }
36
56
  }
57
+ exports.parseBlogFileName = parseBlogFileName;
37
58
  function formatBlogPostDate(locale, date) {
38
59
  try {
39
60
  return new Intl.DateTimeFormat(locale, {
@@ -58,7 +79,7 @@ async function generateBlogFeed(contentPaths, context, options) {
58
79
  }
59
80
  const { feedOptions, routeBasePath } = options;
60
81
  const { url: siteUrl, baseUrl, title, favicon } = siteConfig;
61
- const blogBaseUrl = utils_1.normalizeUrl([siteUrl, baseUrl, routeBasePath]);
82
+ const blogBaseUrl = (0, utils_1.normalizeUrl)([siteUrl, baseUrl, routeBasePath]);
62
83
  const updated = (blogPosts[0] && blogPosts[0].metadata.date) ||
63
84
  new Date('2015-10-25T16:29:00.000-07:00');
64
85
  const feed = new feed_1.Feed({
@@ -68,125 +89,146 @@ async function generateBlogFeed(contentPaths, context, options) {
68
89
  language: feedOptions.language,
69
90
  link: blogBaseUrl,
70
91
  description: feedOptions.description || `${siteConfig.title} Blog`,
71
- favicon: favicon ? utils_1.normalizeUrl([siteUrl, baseUrl, favicon]) : undefined,
92
+ favicon: favicon ? (0, utils_1.normalizeUrl)([siteUrl, baseUrl, favicon]) : undefined,
72
93
  copyright: feedOptions.copyright,
73
94
  });
95
+ function toFeedAuthor(author) {
96
+ // TODO ask author emails?
97
+ // RSS feed requires email to render authors
98
+ return { name: author.name, link: author.url };
99
+ }
74
100
  blogPosts.forEach((post) => {
75
- const { id, metadata: { title: metadataTitle, permalink, date, description }, } = post;
101
+ const { id, metadata: { title: metadataTitle, permalink, date, description, authors }, } = post;
76
102
  feed.addItem({
77
103
  title: metadataTitle,
78
104
  id,
79
- link: utils_1.normalizeUrl([siteUrl, permalink]),
105
+ link: (0, utils_1.normalizeUrl)([siteUrl, permalink]),
80
106
  date,
81
107
  description,
108
+ content: (0, utils_1.mdxToHtml)(post.content),
109
+ author: authors.map(toFeedAuthor),
82
110
  });
83
111
  });
84
112
  return feed;
85
113
  }
86
114
  exports.generateBlogFeed = generateBlogFeed;
87
- async function generateBlogPosts(contentPaths, { siteConfig, siteDir, i18n }, options) {
88
- const { include, routeBasePath, truncateMarker, showReadingTime, editUrl, } = options;
89
- if (!fs_extra_1.default.existsSync(contentPaths.contentPath)) {
90
- return [];
91
- }
92
- const { baseUrl = '' } = siteConfig;
93
- const blogSourceFiles = await globby_1.default(include, {
94
- cwd: contentPaths.contentPath,
115
+ async function parseBlogPostMarkdownFile(blogSourceAbsolute) {
116
+ const result = await (0, utils_1.parseMarkdownFile)(blogSourceAbsolute, {
117
+ removeContentTitle: true,
95
118
  });
96
- const blogPosts = [];
97
- async function processBlogSourceFile(blogSourceFile) {
98
- var _a, _b, _c, _d, _e, _f;
99
- // Lookup in localized folder in priority
100
- const blogDirPath = await utils_1.getFolderContainingFile(getContentPathList(contentPaths), blogSourceFile);
101
- const source = path_1.default.join(blogDirPath, blogSourceFile);
102
- const { frontMatter: unsafeFrontMatter, content, contentTitle, excerpt, } = await utils_1.parseMarkdownFile(source, { removeContentTitle: true });
103
- const frontMatter = blogFrontMatter_1.validateBlogPostFrontMatter(unsafeFrontMatter);
104
- const aliasedSource = utils_1.aliasedSitePath(source, siteDir);
105
- const blogFileName = path_1.default.basename(blogSourceFile);
106
- if (frontMatter.draft && process.env.NODE_ENV === 'production') {
107
- return;
108
- }
109
- if (frontMatter.id) {
110
- console.warn(chalk_1.default.yellow(`"id" header option is deprecated in ${blogFileName} file. Please use "slug" option instead.`));
111
- }
112
- let date;
113
- // Extract date and title from filename.
114
- const dateFilenameMatch = blogFileName.match(DATE_FILENAME_PATTERN);
115
- let linkName = blogFileName.replace(/\.mdx?$/, '');
116
- if (dateFilenameMatch) {
117
- const [, dateString, name] = dateFilenameMatch;
118
- // Always treat dates as UTC by adding the `Z`
119
- date = new Date(`${dateString}Z`);
120
- linkName = name;
121
- }
119
+ return {
120
+ ...result,
121
+ frontMatter: (0, blogFrontMatter_1.validateBlogPostFrontMatter)(result.frontMatter),
122
+ };
123
+ }
124
+ async function processBlogSourceFile(blogSourceRelative, contentPaths, context, options, authorsMap) {
125
+ var _a, _b, _c, _d, _e;
126
+ const { siteConfig: { baseUrl }, siteDir, i18n, } = context;
127
+ const { routeBasePath, tagsBasePath: tagsRouteBasePath, truncateMarker, showReadingTime, editUrl, } = options;
128
+ // Lookup in localized folder in priority
129
+ const blogDirPath = await (0, utils_1.getFolderContainingFile)(getContentPathList(contentPaths), blogSourceRelative);
130
+ const blogSourceAbsolute = path_1.default.join(blogDirPath, blogSourceRelative);
131
+ const { frontMatter, content, contentTitle, excerpt } = await parseBlogPostMarkdownFile(blogSourceAbsolute);
132
+ const aliasedSource = (0, utils_1.aliasedSitePath)(blogSourceAbsolute, siteDir);
133
+ if (frontMatter.draft && process.env.NODE_ENV === 'production') {
134
+ return undefined;
135
+ }
136
+ if (frontMatter.id) {
137
+ console.warn(chalk_1.default.yellow(`"id" header option is deprecated in ${blogSourceRelative} file. Please use "slug" option instead.`));
138
+ }
139
+ const parsedBlogFileName = parseBlogFileName(blogSourceRelative);
140
+ async function getDate() {
122
141
  // Prefer user-defined date.
123
142
  if (frontMatter.date) {
124
- date = frontMatter.date;
143
+ return new Date(frontMatter.date);
125
144
  }
126
- // Use file create time for blog.
127
- date = date !== null && date !== void 0 ? date : (await fs_extra_1.default.stat(source)).birthtime;
128
- const formattedDate = formatBlogPostDate(i18n.currentLocale, date);
129
- const title = (_b = (_a = frontMatter.title) !== null && _a !== void 0 ? _a : contentTitle) !== null && _b !== void 0 ? _b : linkName;
130
- const description = (_d = (_c = frontMatter.description) !== null && _c !== void 0 ? _c : excerpt) !== null && _d !== void 0 ? _d : '';
131
- const slug = frontMatter.slug ||
132
- (dateFilenameMatch ? toUrl({ date, link: linkName }) : linkName);
133
- const permalink = utils_1.normalizeUrl([baseUrl, routeBasePath, slug]);
134
- function getBlogEditUrl() {
135
- const blogPathRelative = path_1.default.relative(blogDirPath, path_1.default.resolve(source));
136
- if (typeof editUrl === 'function') {
137
- return editUrl({
138
- blogDirPath: utils_1.posixPath(path_1.default.relative(siteDir, blogDirPath)),
139
- blogPath: utils_1.posixPath(blogPathRelative),
140
- permalink,
141
- locale: i18n.currentLocale,
142
- });
143
- }
144
- else if (typeof editUrl === 'string') {
145
- const isLocalized = blogDirPath === contentPaths.contentPathLocalized;
146
- const fileContentPath = isLocalized && options.editLocalizedFiles
147
- ? contentPaths.contentPathLocalized
148
- : contentPaths.contentPath;
149
- const contentPathEditUrl = utils_1.normalizeUrl([
150
- editUrl,
151
- utils_1.posixPath(path_1.default.relative(siteDir, fileContentPath)),
152
- ]);
153
- return utils_1.getEditUrl(blogPathRelative, contentPathEditUrl);
154
- }
155
- else {
156
- return undefined;
157
- }
145
+ else if (parsedBlogFileName.date) {
146
+ return parsedBlogFileName.date;
158
147
  }
159
- blogPosts.push({
160
- id: (_e = frontMatter.slug) !== null && _e !== void 0 ? _e : title,
161
- metadata: {
148
+ // Fallback to file create time
149
+ return (await fs_extra_1.default.stat(blogSourceAbsolute)).birthtime;
150
+ }
151
+ const date = await getDate();
152
+ const formattedDate = formatBlogPostDate(i18n.currentLocale, date);
153
+ const title = (_b = (_a = frontMatter.title) !== null && _a !== void 0 ? _a : contentTitle) !== null && _b !== void 0 ? _b : parsedBlogFileName.text;
154
+ const description = (_d = (_c = frontMatter.description) !== null && _c !== void 0 ? _c : excerpt) !== null && _d !== void 0 ? _d : '';
155
+ const slug = frontMatter.slug || parsedBlogFileName.slug;
156
+ const permalink = (0, utils_1.normalizeUrl)([baseUrl, routeBasePath, slug]);
157
+ function getBlogEditUrl() {
158
+ const blogPathRelative = path_1.default.relative(blogDirPath, path_1.default.resolve(blogSourceAbsolute));
159
+ if (typeof editUrl === 'function') {
160
+ return editUrl({
161
+ blogDirPath: (0, utils_1.posixPath)(path_1.default.relative(siteDir, blogDirPath)),
162
+ blogPath: (0, utils_1.posixPath)(blogPathRelative),
162
163
  permalink,
163
- editUrl: getBlogEditUrl(),
164
- source: aliasedSource,
165
- title,
166
- description,
167
- date,
168
- formattedDate,
169
- tags: (_f = frontMatter.tags) !== null && _f !== void 0 ? _f : [],
170
- readingTime: showReadingTime ? reading_time_1.default(content).minutes : undefined,
171
- truncated: (truncateMarker === null || truncateMarker === void 0 ? void 0 : truncateMarker.test(content)) || false,
172
- },
173
- });
164
+ locale: i18n.currentLocale,
165
+ });
166
+ }
167
+ else if (typeof editUrl === 'string') {
168
+ const isLocalized = blogDirPath === contentPaths.contentPathLocalized;
169
+ const fileContentPath = isLocalized && options.editLocalizedFiles
170
+ ? contentPaths.contentPathLocalized
171
+ : contentPaths.contentPath;
172
+ const contentPathEditUrl = (0, utils_1.normalizeUrl)([
173
+ editUrl,
174
+ (0, utils_1.posixPath)(path_1.default.relative(siteDir, fileContentPath)),
175
+ ]);
176
+ return (0, utils_1.getEditUrl)(blogPathRelative, contentPathEditUrl);
177
+ }
178
+ return undefined;
179
+ }
180
+ const tagsBasePath = (0, utils_1.normalizeUrl)([
181
+ baseUrl,
182
+ routeBasePath,
183
+ tagsRouteBasePath,
184
+ ]);
185
+ const authors = (0, authors_1.getBlogPostAuthors)({ authorsMap, frontMatter });
186
+ return {
187
+ id: (_e = frontMatter.slug) !== null && _e !== void 0 ? _e : title,
188
+ metadata: {
189
+ permalink,
190
+ editUrl: getBlogEditUrl(),
191
+ source: aliasedSource,
192
+ title,
193
+ description,
194
+ date,
195
+ formattedDate,
196
+ tags: (0, utils_1.normalizeFrontMatterTags)(tagsBasePath, frontMatter.tags),
197
+ readingTime: showReadingTime ? (0, reading_time_1.default)(content).minutes : undefined,
198
+ truncated: (truncateMarker === null || truncateMarker === void 0 ? void 0 : truncateMarker.test(content)) || false,
199
+ authors,
200
+ },
201
+ content,
202
+ };
203
+ }
204
+ async function generateBlogPosts(contentPaths, context, options) {
205
+ const { include, exclude } = options;
206
+ if (!fs_extra_1.default.existsSync(contentPaths.contentPath)) {
207
+ return [];
174
208
  }
175
- await Promise.all(blogSourceFiles.map(async (blogSourceFile) => {
209
+ const blogSourceFiles = await (0, utils_1.Globby)(include, {
210
+ cwd: contentPaths.contentPath,
211
+ ignore: exclude,
212
+ });
213
+ const authorsMap = await (0, authors_1.getAuthorsMap)({
214
+ contentPaths,
215
+ authorsMapPath: options.authorsMapPath,
216
+ });
217
+ const blogPosts = (0, lodash_1.compact)(await Promise.all(blogSourceFiles.map(async (blogSourceFile) => {
176
218
  try {
177
- return await processBlogSourceFile(blogSourceFile);
219
+ return await processBlogSourceFile(blogSourceFile, contentPaths, context, options, authorsMap);
178
220
  }
179
221
  catch (e) {
180
222
  console.error(chalk_1.default.red(`Processing of blog source file failed for path "${blogSourceFile}"`));
181
223
  throw e;
182
224
  }
183
- }));
225
+ })));
184
226
  blogPosts.sort((a, b) => b.metadata.date.getTime() - a.metadata.date.getTime());
185
227
  return blogPosts;
186
228
  }
187
229
  exports.generateBlogPosts = generateBlogPosts;
188
230
  function linkify({ filePath, contentPaths, fileString, siteDir, sourceToPermalink, onBrokenMarkdownLink, }) {
189
- const { newContent, brokenMarkdownLinks } = utils_1.replaceMarkdownLinks({
231
+ const { newContent, brokenMarkdownLinks } = (0, utils_1.replaceMarkdownLinks)({
190
232
  siteDir,
191
233
  fileString,
192
234
  filePath,