feat(blog-plugin): limit option for blog feedOptions (#9189)

This commit is contained in:
John Reilly 2023-08-03 14:53:43 +01:00 committed by GitHub
parent e0bb39a40a
commit 4ecc86f89f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 164 additions and 8 deletions

File diff suppressed because one or more lines are too long

View file

@ -195,4 +195,47 @@ describe.each(['atom', 'rss', 'json'])('%s', (feedType) => {
).toMatchSnapshot(); ).toMatchSnapshot();
fsMock.mockClear(); fsMock.mockClear();
}); });
it('filters to the first two entries using limit', async () => {
const siteDir = path.join(__dirname, '__fixtures__', 'website');
const outDir = path.join(siteDir, 'build-snap');
const siteConfig = {
title: 'Hello',
baseUrl: '/myBaseUrl/',
url: 'https://docusaurus.io',
favicon: 'image/favicon.ico',
};
// Build is quite difficult to mock, so we built the blog beforehand and
// copied the output to the fixture...
await testGenerateFeeds(
{
siteDir,
siteConfig,
i18n: DefaultI18N,
outDir,
} as LoadContext,
{
path: 'blog',
routeBasePath: 'blog',
tagsBasePath: 'tags',
authorsMapPath: 'authors.yml',
include: DEFAULT_OPTIONS.include,
exclude: DEFAULT_OPTIONS.exclude,
feedOptions: {
type: [feedType],
copyright: 'Copyright',
limit: 2,
},
readingTime: ({content, defaultReadingTime}) =>
defaultReadingTime({content}),
truncateMarker: /<!--\s*truncate\s*-->/,
} as PluginOptions,
);
expect(
fsMock.mock.calls.map((call) => call[1] as string),
).toMatchSnapshot();
fsMock.mockClear();
});
}); });

View file

@ -46,7 +46,7 @@ describe('validateOptions', () => {
}; };
expect(testValidate(userOptions)).toEqual({ expect(testValidate(userOptions)).toEqual({
...userOptions, ...userOptions,
feedOptions: {type: ['rss'], title: 'myTitle', copyright: ''}, feedOptions: {type: ['rss'], title: 'myTitle', copyright: '', limit: 20},
}); });
}); });
@ -58,7 +58,6 @@ describe('validateOptions', () => {
beforeDefaultRehypePlugins: [markdownPluginsFunctionStub], beforeDefaultRehypePlugins: [markdownPluginsFunctionStub],
remarkPlugins: [[markdownPluginsFunctionStub, {option1: '42'}]], remarkPlugins: [[markdownPluginsFunctionStub, {option1: '42'}]],
rehypePlugins: [ rehypePlugins: [
// @ts-expect-error: it seems to work in practice
markdownPluginsObjectStub, markdownPluginsObjectStub,
[markdownPluginsFunctionStub, {option1: '42'}], [markdownPluginsFunctionStub, {option1: '42'}],
], ],
@ -95,7 +94,7 @@ describe('validateOptions', () => {
}), }),
).toEqual({ ).toEqual({
...defaultOptions, ...defaultOptions,
feedOptions: {type: ['rss', 'atom', 'json'], copyright: ''}, feedOptions: {type: ['rss', 'atom', 'json'], copyright: '', limit: 20},
}); });
}); });
@ -106,7 +105,7 @@ describe('validateOptions', () => {
}), }),
).toEqual({ ).toEqual({
...defaultOptions, ...defaultOptions,
feedOptions: {type: null}, feedOptions: {type: null, limit: 20},
}); });
}); });
@ -125,7 +124,12 @@ describe('validateOptions', () => {
}), }),
).toEqual({ ).toEqual({
...defaultOptions, ...defaultOptions,
feedOptions: {type: ['rss', 'atom'], title: 'title', copyright: ''}, feedOptions: {
type: ['rss', 'atom'],
title: 'title',
copyright: '',
limit: 20,
},
}); });
}); });

View file

@ -42,7 +42,12 @@ async function generateBlogFeed({
const {url: siteUrl, baseUrl, title, favicon} = siteConfig; const {url: siteUrl, baseUrl, title, favicon} = siteConfig;
const blogBaseUrl = normalizeUrl([siteUrl, baseUrl, routeBasePath]); const blogBaseUrl = normalizeUrl([siteUrl, baseUrl, routeBasePath]);
const updated = blogPosts[0]?.metadata.date; const blogPostsForFeed =
feedOptions.limit === false || feedOptions.limit === null
? blogPosts
: blogPosts.slice(0, feedOptions.limit);
const updated = blogPostsForFeed[0]?.metadata.date;
const feed = new Feed({ const feed = new Feed({
id: blogBaseUrl, id: blogBaseUrl,
@ -59,7 +64,7 @@ async function generateBlogFeed({
options.feedOptions.createFeedItems ?? defaultCreateFeedItems; options.feedOptions.createFeedItems ?? defaultCreateFeedItems;
const feedItems = await createFeedItems({ const feedItems = await createFeedItems({
blogPosts, blogPosts: blogPostsForFeed,
siteConfig, siteConfig,
outDir, outDir,
defaultCreateFeedItems, defaultCreateFeedItems,

View file

@ -22,7 +22,7 @@ import type {
import type {OptionValidationContext} from '@docusaurus/types'; import type {OptionValidationContext} from '@docusaurus/types';
export const DEFAULT_OPTIONS: PluginOptions = { export const DEFAULT_OPTIONS: PluginOptions = {
feedOptions: {type: ['rss', 'atom'], copyright: ''}, feedOptions: {type: ['rss', 'atom'], copyright: '', limit: 20},
beforeDefaultRehypePlugins: [], beforeDefaultRehypePlugins: [],
beforeDefaultRemarkPlugins: [], beforeDefaultRemarkPlugins: [],
admonitions: true, admonitions: true,
@ -123,6 +123,9 @@ const PluginOptionSchema = Joi.object<PluginOptions>({
}), }),
language: Joi.string(), language: Joi.string(),
createFeedItems: Joi.function(), createFeedItems: Joi.function(),
limit: Joi.alternatives()
.try(Joi.number(), Joi.valid(null), Joi.valid(false))
.default(DEFAULT_OPTIONS.feedOptions.limit),
}).default(DEFAULT_OPTIONS.feedOptions), }).default(DEFAULT_OPTIONS.feedOptions),
authorsMapPath: Joi.string().default(DEFAULT_OPTIONS.authorsMapPath), authorsMapPath: Joi.string().default(DEFAULT_OPTIONS.authorsMapPath),
readingTime: Joi.function().default(() => DEFAULT_OPTIONS.readingTime), readingTime: Joi.function().default(() => DEFAULT_OPTIONS.readingTime),

View file

@ -272,6 +272,8 @@ yarn workspace v1.22.19image` is a collocated image path, this entry will be the
language?: string; language?: string;
/** Allow control over the construction of BlogFeedItems */ /** Allow control over the construction of BlogFeedItems */
createFeedItems?: CreateFeedItemsFn; createFeedItems?: CreateFeedItemsFn;
/** Limits the feed to the specified number of posts, false|null for all */
limit?: number | false | null;
}; };
type DefaultCreateFeedItemsParams = { type DefaultCreateFeedItemsParams = {

View file

@ -68,6 +68,7 @@ Accepted fields:
| `feedOptions` | _See below_ | `{type: ['rss', 'atom']}` | Blog feed. | | `feedOptions` | _See below_ | `{type: ['rss', 'atom']}` | Blog feed. |
| `feedOptions.type` | <code><a href="#FeedType">FeedType</a> \| <a href="#FeedType">FeedType</a>[] \| 'all' \| null</code> | **Required** | Type of feed to be generated. Use `null` to disable generation. | | `feedOptions.type` | <code><a href="#FeedType">FeedType</a> \| <a href="#FeedType">FeedType</a>[] \| 'all' \| null</code> | **Required** | Type of feed to be generated. Use `null` to disable generation. |
| `feedOptions.createFeedItems` | <code><a href="#CreateFeedItemsFn">CreateFeedItemsFn</a> \| undefined</code> | `undefined` | An optional function which can be used to transform and / or filter the items in the feed. | | `feedOptions.createFeedItems` | <code><a href="#CreateFeedItemsFn">CreateFeedItemsFn</a> \| undefined</code> | `undefined` | An optional function which can be used to transform and / or filter the items in the feed. |
| `feedOptions.limit` | `number \| null \| false` | `20` | Limits the feed to the specified number of posts, `false` or `null` for all entries. Defaults to `20`. |
| `feedOptions.title` | `string` | `siteConfig.title` | Title of the feed. | | `feedOptions.title` | `string` | `siteConfig.title` | Title of the feed. |
| `feedOptions.description` | `string` | <code>\`$\{siteConfig.title} Blog\`</code> | Description of the feed. | | `feedOptions.description` | `string` | <code>\`$\{siteConfig.title} Blog\`</code> | Description of the feed. |
| `feedOptions.copyright` | `string` | `undefined` | Copyright message. | | `feedOptions.copyright` | `string` | `undefined` | Copyright message. |

View file

@ -520,6 +520,7 @@ type BlogOptions = {
description?: string; description?: string;
copyright: string; copyright: string;
language?: string; // possible values: http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes language?: string; // possible values: http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes
limit?: number | false | null; // defaults to 20
/** Allow control over the construction of BlogFeedItems */ /** Allow control over the construction of BlogFeedItems */
createFeedItems?: (params: { createFeedItems?: (params: {
blogPosts: BlogPost[]; blogPosts: BlogPost[];