@docusaurus/plugin-content-blog 2.0.0-beta.15a2b59f9 → 2.0.0-beta.17

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