Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 3 commits into from Aug 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view

Large diffs are not rendered by default.

Expand Up @@ -195,4 +195,47 @@ describe.each(['atom', 'rss', 'json'])('%s', (feedType) => {
).toMatchSnapshot();
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();
});
});
Expand Up @@ -46,7 +46,7 @@ describe('validateOptions', () => {
};
expect(testValidate(userOptions)).toEqual({
...userOptions,
feedOptions: {type: ['rss'], title: 'myTitle', copyright: ''},
feedOptions: {type: ['rss'], title: 'myTitle', copyright: '', limit: 20},
});
});

Expand All @@ -58,7 +58,6 @@ describe('validateOptions', () => {
beforeDefaultRehypePlugins: [markdownPluginsFunctionStub],
remarkPlugins: [[markdownPluginsFunctionStub, {option1: '42'}]],
rehypePlugins: [
// @ts-expect-error: it seems to work in practice
markdownPluginsObjectStub,
[markdownPluginsFunctionStub, {option1: '42'}],
],
Expand Down Expand Up @@ -95,7 +94,7 @@ describe('validateOptions', () => {
}),
).toEqual({
...defaultOptions,
feedOptions: {type: ['rss', 'atom', 'json'], copyright: ''},
feedOptions: {type: ['rss', 'atom', 'json'], copyright: '', limit: 20},
});
});

Expand All @@ -106,7 +105,7 @@ describe('validateOptions', () => {
}),
).toEqual({
...defaultOptions,
feedOptions: {type: null},
feedOptions: {type: null, limit: 20},
});
});

Expand All @@ -125,7 +124,12 @@ describe('validateOptions', () => {
}),
).toEqual({
...defaultOptions,
feedOptions: {type: ['rss', 'atom'], title: 'title', copyright: ''},
feedOptions: {
type: ['rss', 'atom'],
title: 'title',
copyright: '',
limit: 20,
},
});
});

Expand Down
9 changes: 7 additions & 2 deletions packages/docusaurus-plugin-content-blog/src/feed.ts
Expand Up @@ -42,7 +42,12 @@ async function generateBlogFeed({
const {url: siteUrl, baseUrl, title, favicon} = siteConfig;
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({
id: blogBaseUrl,
Expand All @@ -59,7 +64,7 @@ async function generateBlogFeed({
options.feedOptions.createFeedItems ?? defaultCreateFeedItems;

const feedItems = await createFeedItems({
blogPosts,
blogPosts: blogPostsForFeed,
siteConfig,
outDir,
defaultCreateFeedItems,
Expand Down
5 changes: 4 additions & 1 deletion packages/docusaurus-plugin-content-blog/src/options.ts
Expand Up @@ -22,7 +22,7 @@ import type {
import type {OptionValidationContext} from '@docusaurus/types';

export const DEFAULT_OPTIONS: PluginOptions = {
feedOptions: {type: ['rss', 'atom'], copyright: ''},
feedOptions: {type: ['rss', 'atom'], copyright: '', limit: 20},
beforeDefaultRehypePlugins: [],
beforeDefaultRemarkPlugins: [],
admonitions: true,
Expand Down Expand Up @@ -123,6 +123,9 @@ const PluginOptionSchema = Joi.object<PluginOptions>({
}),
language: Joi.string(),
createFeedItems: Joi.function(),
limit: Joi.alternatives()
.try(Joi.number(), Joi.valid(null), Joi.valid(false))
.default(DEFAULT_OPTIONS.feedOptions.limit),
}).default(DEFAULT_OPTIONS.feedOptions),
authorsMapPath: Joi.string().default(DEFAULT_OPTIONS.authorsMapPath),
readingTime: Joi.function().default(() => DEFAULT_OPTIONS.readingTime),
Expand Down
Expand Up @@ -272,6 +272,8 @@ yarn workspace v1.22.19image` is a collocated image path, this entry will be the
language?: string;
/** Allow control over the construction of BlogFeedItems */
createFeedItems?: CreateFeedItemsFn;
/** Limits the feed to the specified number of posts, false|null for all */
limit?: number | false | null;
};

type DefaultCreateFeedItemsParams = {
Expand Down
1 change: 1 addition & 0 deletions website/docs/api/plugins/plugin-content-blog.mdx
Expand Up @@ -68,6 +68,7 @@ Accepted fields:
| `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.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.description` | `string` | <code>\`$\{siteConfig.title} Blog\`</code> | Description of the feed. |
| `feedOptions.copyright` | `string` | `undefined` | Copyright message. |
Expand Down
1 change: 1 addition & 0 deletions website/docs/blog.mdx
Expand Up @@ -520,6 +520,7 @@ type BlogOptions = {
description?: string;
copyright: string;
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 */
createFeedItems?: (params: {
blogPosts: BlogPost[];
Expand Down