mirror of
https://github.com/facebook/docusaurus.git
synced 2025-04-29 18:27:56 +02:00
feat(blog-plugin): limit option for blog feedOptions (#9189)
This commit is contained in:
parent
e0bb39a40a
commit
4ecc86f89f
8 changed files with 164 additions and 8 deletions
File diff suppressed because one or more lines are too long
|
@ -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();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -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,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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 = {
|
||||||
|
|
|
@ -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. |
|
||||||
|
|
|
@ -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[];
|
||||||
|
|
Loading…
Add table
Reference in a new issue